made mistakes more safe (no more infinite loops)

This commit is contained in:
Bram Dingelstad 2021-12-07 10:07:11 +01:00
parent c1bcd24694
commit 753a504604
3 changed files with 33 additions and 28 deletions

View file

@ -130,6 +130,8 @@ func assert(statement, message, line_number = -1, column = -1, _absolute_line_nu
elif not statement: elif not statement:
emit_signal('error', message, line_number, column) emit_signal('error', message, line_number, column)
return not statement
func compile(): func compile():
var parsed_nodes = [] var parsed_nodes = []
for node in get_nodes(): for node in get_nodes():

View file

@ -37,15 +37,13 @@ func next_symbols_are(valid_types):
return true return true
func expect_symbol(token_types = []): func expect_symbol(token_types = []):
compiler.assert(tokens.size() != 0, 'Ran out of tokens expecting next symbol!') if compiler.assert(tokens.size() != 0, 'Ran out of tokens expecting next symbol!'):
return
var token = tokens.pop_front() as Lexer.Token var token = tokens.pop_front() as Lexer.Token
if tokens.size() == 0:
return token
if token_types.size() == 0: if token_types.size() == 0:
if token.type == Constants.TokenType.EndOfInput: compiler.assert(token.type != Constants.TokenType.EndOfInput, 'Unexpected end of input')
compiler.assert(false, 'Unexpected end of input')
return token return token
for type in token_types: for type in token_types:
@ -70,7 +68,7 @@ func expect_symbol(token_types = []):
error_guess error_guess
] ]
compiler.assert(false, 'Expected token "%s" but got "%s"%s' % error_data, token.line_number, token.column) compiler.assert(false, 'Expected token "%s" but got "%s"%s' % error_data, token.line_number, token.column)
return token return
static func tab(indent_level, input, newline = true): static func tab(indent_level, input, newline = true):
return '%*s| %s%s' % [indent_level * 2, '', input, '' if not newline else '\n'] return '%*s| %s%s' % [indent_level * 2, '', input, '' if not newline else '\n']
@ -128,7 +126,11 @@ class WolNode extends ParseNode:
parser.tokens.front().column parser.tokens.front().column
) )
statements.append(Statement.new(self, parser)) var statement = Statement.new(self, parser)
if statement.failed_to_parse:
break
statements.append(statement)
func tree_string(indent_level): func tree_string(indent_level):
var info = [] var info = []
@ -148,6 +150,7 @@ class Statement extends ParseNode:
var shortcut_option_group var shortcut_option_group
var custom_command var custom_command
var line var line
var failed_to_parse = false
func _init(parent, parser).(parent, parser): func _init(parent, parser).(parent, parser):
if Block.can_parse(parser): if Block.can_parse(parser):
@ -180,6 +183,8 @@ class Statement extends ParseNode:
else: else:
parser.compiler.assert(false, 'Expected a statement but got %s instead. (probably an imbalanced if statement)' % parser.tokens.front()._to_string()) parser.compiler.assert(false, 'Expected a statement but got %s instead. (probably an imbalanced if statement)' % parser.tokens.front()._to_string())
failed_to_parse = true
return
var tags = [] var tags = []
@ -210,7 +215,7 @@ class Statement extends ParseNode:
Type.Line: Type.Line:
info.append(line.tree_string(indent_level)) info.append(line.tree_string(indent_level))
_: _:
printerr('Cannot print statement') self.parser.compiler.assert(false, 'Cannot print statement')
return PoolStringArray(info).join('') return PoolStringArray(info).join('')
@ -297,7 +302,7 @@ class LineNode extends ParseNode:
if line_id.empty(): if line_id.empty():
line_id = tag_token.value line_id = tag_token.value
else: else:
printerr("Too many line_tags @[%s:%d]" % [parser.currentNodeName, tag_token.line_number]) parser.compiler.assert(false, 'Too many line_tags @[%s:%d]' % [parser.currentNodeName, tag_token.line_number])
return return
else: else:
tags.append(tag_token.value) tags.append(tag_token.value)
@ -642,7 +647,7 @@ class ValueNode extends ParseNode:
Constants.TokenType.NullToken: Constants.TokenType.NullToken:
value = Value.new(null) value = Value.new(null)
_: _:
printerr('%s, Invalid token type' % token.name) self.parser.compiler.assert(false, '%s, Invalid token type' % token.name)
func tree_string(indent_level): func tree_string(indent_level):
return tab(indent_level, '%s' % value.value()) return tab(indent_level, '%s' % value.value())
@ -736,16 +741,15 @@ class ExpressionNode extends ParseNode:
while op_stack.back().type != Constants.TokenType.LeftParen: while op_stack.back().type != Constants.TokenType.LeftParen:
var p = op_stack.pop_back() var p = op_stack.pop_back()
if p == null: if p == null:
printerr('unbalanced parenthesis %s' % next.name) parser.compiler.assert(false, 'unbalanced parenthesis %s' % next.name)
break break
rpn.append(p) rpn.append(p)
#next token in op_stack left paren #next token in op_stack left paren
# next parser token not allowed to be right paren or comma # next parser token not allowed to be right paren or comma
if parser.next_symbol_is([Constants.TokenType.RightParen, if parser.next_symbol_is([Constants.TokenType.RightParen, Constants.TokenType.Comma]):
Constants.TokenType.Comma]): parser.compiler.assert(false, 'Expected Expression : %s' % parser.tokens.front().name)
printerr('Expected Expression : %s' % parser.tokens.front().name)
#find the closest function on stack #find the closest function on stack
#increment parameters #increment parameters
@ -823,7 +827,7 @@ class ExpressionNode extends ParseNode:
#if rpn is empty then this is not expression #if rpn is empty then this is not expression
if rpn.size() == 0: if rpn.size() == 0:
printerr('Error parsing expression: Expression not found!') parser.compiler.assert(false, 'Error parsing expression: Expression not found!')
#build expression tree #build expression tree
var first = rpn.front() var first = rpn.front()
@ -833,10 +837,10 @@ class ExpressionNode extends ParseNode:
var next = rpn.pop_front() var next = rpn.pop_front()
if Operator.is_op(next.type): if Operator.is_op(next.type):
#operation #operation
var info = Operator.op_info(next.type) var info = Operator.op_info(next.type, parser)
if eval_stack.size() < info.arguments: if eval_stack.size() < info.arguments:
printerr( parser.compiler.assert(false,
'Error parsing : Not enough arguments for %s [ got %s expected - was %s]' \ 'Error parsing : Not enough arguments for %s [ got %s expected - was %s]' \
% [ % [
Constants.token_type_name(next.type), Constants.token_type_name(next.type),
@ -900,8 +904,7 @@ class ExpressionNode extends ParseNode:
if operator_stack.size() == 0: if operator_stack.size() == 0:
return false return false
if not Operator.is_op(_type): if parser.compiler.assert(Operator.is_op(_type), 'Unable to parse expression!'):
parser.compiler.assert(false, 'Unable to parse expression!')
return false return false
var second = operator_stack.back().type var second = operator_stack.back().type
@ -909,8 +912,8 @@ class ExpressionNode extends ParseNode:
if not Operator.is_op(second): if not Operator.is_op(second):
return false return false
var first_info = Operator.op_info(_type) var first_info = Operator.op_info(_type, parser)
var second_info = Operator.op_info(second) var second_info = Operator.op_info(second, parser)
return \ return \
(first_info.associativity == Associativity.Left \ (first_info.associativity == Associativity.Left \
@ -970,9 +973,9 @@ class Operator extends ParseNode:
info.append(tab(indent_level, op_type)) info.append(tab(indent_level, op_type))
return info.join('') return info.join('')
static func op_info(op): static func op_info(op, parser):
if not Operator.is_op(op) : if parser.compiler.assert(Operator.is_op(op), '%s is not a valid operator' % op):
printerr('%s is not a valid operator' % op.name) return
#determine associativity and operands #determine associativity and operands
# each operand has # each operand has
@ -996,8 +999,8 @@ class Operator extends ParseNode:
TokenType.Xor: TokenType.Xor:
return OperatorInfo.new(Associativity.Left, 2, 2) return OperatorInfo.new(Associativity.Left, 2, 2)
_: _:
printerr('Unknown operator: %s' % op.name) parser.compiler.assert(false, 'Unknown operator: %s' % op.name)
return null return
static func is_op(type): static func is_op(type):
return type in op_types() return type in op_types()

View file

@ -48,7 +48,7 @@ func get_connections():
return connections return connections
func _on_text_changed(): func _on_text_changed():
$TextDebounce.start(.3) $TextDebounce.start()
func _on_debounce(): func _on_debounce():
text_edit.get_node('ErrorGutter').hide() text_edit.get_node('ErrorGutter').hide()