made mistakes more safe (no more infinite loops)
This commit is contained in:
parent
c1bcd24694
commit
753a504604
|
@ -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():
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Reference in a new issue