replaced a bunch of other stuff

This commit is contained in:
Bram Dingelstad 2021-11-20 14:51:10 +01:00
parent e3bac32178
commit 611fc399ae
3 changed files with 270 additions and 271 deletions

View file

@ -17,18 +17,18 @@ const DUPLICATE_NODES_IN_PROGRAM = 0x08
const ERR_COMPILATION_FAILED = 0x10
var _errors : int
var _lastError : int
var _last_error : int
#-----Class vars
var _currentNode : Program.WolNode
var _rawText : bool
var _fileName : String
var _containsImplicitStringTags : bool
var _labelCount : int = 0
var _current_node : Program.WolNode
var _raw_text : bool
var _file_name : String
var _contains_implicit_string_tags : bool
var _label_count : int = 0
#<String, Program.Line>
var _stringTable : Dictionary = {}
var _stringCount : int = 0
var _string_table : Dictionary = {}
var _string_count : int = 0
#<int, Constants.TokenType>
var _tokens : Dictionary = {}
@ -37,36 +37,36 @@ static func compile_string(source: String, filename: String):
var Compiler = load('res://addons/Wol/core/compiler/compiler.gd')
var compiler = Compiler.new()
compiler._fileName = filename
compiler._file_name = filename
#--------------Nodes
var headerSep : RegEx = RegEx.new()
headerSep.compile('---(\r\n|\r|\n)')
var headerProperty : RegEx = RegEx.new()
headerProperty.compile('(?<field>.*): *(?<value>.*)')
var header_sep : RegEx = RegEx.new()
header_sep.compile('---(\r\n|\r|\n)')
var header_property : RegEx = RegEx.new()
header_property.compile('(?<field>.*): *(?<value>.*)')
assert(not not headerSep.search(source), 'No headers found')
assert(not not header_sep.search(source), 'No headers found')
var lineNumber: int = 0
var line_number: int = 0
var sourceLines : Array = source.split('\n',false)
for i in range(sourceLines.size()):
sourceLines[i] = sourceLines[i].strip_edges(false,true)
var source_lines : Array = source.split('\n',false)
for i in range(source_lines.size()):
source_lines[i] = source_lines[i].strip_edges(false,true)
var parsedNodes : Array = []
var parsed_nodes : Array = []
while lineNumber < sourceLines.size():
while line_number < source_lines.size():
var title : String
var body : String
#get title
while true:
var line : String = sourceLines[lineNumber]
lineNumber+=1
var line : String = source_lines[line_number]
line_number+=1
if !line.empty():
var result = headerProperty.search(line)
var result = header_property.search(line)
if result != null :
var field : String = result.get_string('field')
var value : String = result.get_string('value')
@ -74,125 +74,125 @@ static func compile_string(source: String, filename: String):
if field == 'title':
title = value
if(lineNumber >= sourceLines.size() || sourceLines[lineNumber] == '---'):
if(line_number >= source_lines.size() || source_lines[line_number] == '---'):
break
lineNumber+=1
line_number+=1
#past header
var bodyLines : PoolStringArray = []
var body_lines : PoolStringArray = []
while lineNumber < sourceLines.size() && sourceLines[lineNumber]!='===':
bodyLines.append(sourceLines[lineNumber])
lineNumber+=1
while line_number < source_lines.size() && source_lines[line_number]!='===':
body_lines.append(source_lines[line_number])
line_number+=1
lineNumber+=1
line_number+=1
body = bodyLines.join('\n')
body = body_lines.join('\n')
var lexer = Lexer.new()
var tokens : Array = lexer.tokenize(body)
var parser = Parser.new(tokens)
var parserNode = parser.parse_node()
var parser_node = parser.parse_node()
parserNode.name = title
parsedNodes.append(parserNode)
while lineNumber < sourceLines.size() && sourceLines[lineNumber].empty():
lineNumber+=1
parser_node.name = title
parsed_nodes.append(parser_node)
while line_number < source_lines.size() && source_lines[line_number].empty():
line_number+=1
#--- End parsing nodes---
var program = Program.new()
#compile nodes
for node in parsedNodes:
for node in parsed_nodes:
compiler.compile_node(program, node)
for key in compiler._stringTable:
program.strings[key] = compiler._stringTable[key]
for key in compiler._string_table:
program.strings[key] = compiler._string_table[key]
return program
func compile_node(program, parsedNode):
if program.nodes.has(parsedNode.name):
func compile_node(program, parsed_node):
if program.nodes.has(parsed_node.name):
emit_error(DUPLICATE_NODES_IN_PROGRAM)
printerr('Duplicate node in program: %s' % parsedNode.name)
printerr('Duplicate node in program: %s' % parsed_node.name)
else:
var nodeCompiled = Program.WolNode.new()
var node_compiled = Program.WolNode.new()
nodeCompiled.name = parsedNode.name
nodeCompiled.tags = parsedNode.tags
node_compiled.name = parsed_node.name
node_compiled.tags = parsed_node.tags
#raw text
if parsedNode.source != null && !parsedNode.source.empty():
nodeCompiled.sourceId = register_string(parsedNode.source,parsedNode.name,
'line:'+parsedNode.name, 0, [])
if parsed_node.source != null && !parsed_node.source.empty():
node_compiled.source_id = register_string(parsed_node.source,parsed_node.name,
'line:'+parsed_node.name, 0, [])
else:
#compile node
var startLabel : String = register_label()
emit(Constants.ByteCode.Label,nodeCompiled,[Program.Operand.new(startLabel)])
var start_label : String = register_label()
emit(Constants.ByteCode.Label,node_compiled,[Program.Operand.new(start_label)])
for statement in parsedNode.statements:
generate_statement(nodeCompiled,statement)
for statement in parsed_node.statements:
generate_statement(node_compiled,statement)
#add options
#todo: add parser flag
var danglingOptions = false
for instruction in nodeCompiled.instructions :
var dangling_options = false
for instruction in node_compiled.instructions :
if instruction.operation == Constants.ByteCode.AddOption:
danglingOptions = true
dangling_options = true
if instruction.operation == Constants.ByteCode.ShowOptions:
danglingOptions = false
dangling_options = false
if danglingOptions:
emit(Constants.ByteCode.ShowOptions, nodeCompiled)
emit(Constants.ByteCode.RunNode, nodeCompiled)
if dangling_options:
emit(Constants.ByteCode.ShowOptions, node_compiled)
emit(Constants.ByteCode.Run_node, node_compiled)
else:
emit(Constants.ByteCode.Stop, nodeCompiled)
emit(Constants.ByteCode.Stop, node_compiled)
program.nodes[nodeCompiled.name] = nodeCompiled
program.nodes[node_compiled.name] = node_compiled
func register_string(text:String,nodeName:String,id:String='',lineNumber:int=-1,tags:Array=[])->String:
var lineIdUsed : String
func register_string(text:String,node_name:String,id:String='',line_number:int=-1,tags:Array=[])->String:
var line_id_used : String
var implicit : bool
if id.empty():
lineIdUsed = '%s-%s-%d' % [self._fileName,nodeName,self._stringCount]
self._stringCount+=1
line_id_used = '%s-%s-%d' % [self._file_name,node_name,self._string_count]
self._string_count+=1
#use this when we generate implicit tags
#they are not saved and are generated
#aka dummy tags that change on each compilation
_containsImplicitStringTags = true
_contains_implicit_string_tags = true
implicit = true
else :
lineIdUsed = id
line_id_used = id
implicit = false
var stringInfo = Program.Line.new(text,nodeName,lineNumber,_fileName,implicit,tags)
var string_info = Program.Line.new(text,node_name,line_number,_file_name,implicit,tags)
#add to string table and return id
self._stringTable[lineIdUsed] = stringInfo
self._string_table[line_id_used] = string_info
return lineIdUsed
return line_id_used
func register_label(comment:String='')->String:
_labelCount+=1
return 'L%s%s' %[ _labelCount , comment]
_label_count+=1
return 'L%s%s' %[ _label_count , comment]
func emit(bytecode, node = _currentNode, operands = []):
func emit(bytecode, node = _current_node, operands = []):
var instruction = Program.Instruction.new(null)
instruction.operation = bytecode
instruction.operands = operands
if node == null:
printerr('trying to emit to null node with byteCode: %s' % bytecode)
printerr('trying to emit to null node with byte_code: %s' % bytecode)
return
node.instructions.append(instruction)
@ -240,61 +240,61 @@ func generate_custom_command(node,command):
if command.expression != null:
generate_expression(node,command.expression)
else:
var commandString = command.client_command
if commandString == 'stop':
var command_string = command.client_command
if command_string == 'stop':
emit(Constants.ByteCode.Stop,node)
else :
emit(Constants.ByteCode.RunCommand,node,[Program.Operand.new(commandString)])
emit(Constants.ByteCode.RunCommand,node,[Program.Operand.new(command_string)])
#compile instructions for linetags and use them
# \#line:number
func generate_line(node,statement,line:String):
var num : String = register_string(line, node.name, '', statement.lineNumber, []);
var num : String = register_string(line, node.name, '', statement.line_number, []);
emit(Constants.ByteCode.RunLine, node, [Program.Operand.new(num)])
func generate_shortcut_group(node,shortcutGroup):
func generate_shortcut_group(node,shortcut_group):
# print('generating shortcutoptopn group')
var end : String = register_label('group_end')
var labels : Array = []#String
var optionCount : int = 0
var option_count : int = 0
for option in shortcutGroup.options:
var opDestination : String = register_label('option_%s'%[optionCount+1])
labels.append(opDestination)
for option in shortcut_group.options:
var op_destination : String = register_label('option_%s'%[option_count+1])
labels.append(op_destination)
var endofClause : String = ''
var endof_clause : String = ''
if option.condition != null :
endofClause = register_label('conditional_%s'%optionCount)
endof_clause = register_label('conditional_%s'%option_count)
generate_expression(node,option.condition)
emit(Constants.ByteCode.JumpIfFalse,node,[Program.Operand.new(endofClause)])
emit(Constants.ByteCode.Jump_if_false,node,[Program.Operand.new(endof_clause)])
var labelLineId : String = ''#no tag TODO: ADD TAG SUPPORT
var labelStringId : String = register_string(option.label,node.nodeName,
labelLineId,option.lineNumber,[])
var label_line_id : String = ''#no tag TODO: ADD TAG SUPPORT
var label_string_id : String = register_string(option.label,node.node_name,
label_line_id,option.line_number,[])
emit(Constants.ByteCode.AddOption,node,[Program.Operand.new(labelStringId),Program.Operand.new(opDestination)])
emit(Constants.ByteCode.AddOption,node,[Program.Operand.new(label_string_id),Program.Operand.new(op_destination)])
if option.condition != null :
emit(Constants.ByteCode.Label,node,[Program.Operand.new(endofClause)])
emit(Constants.ByteCode.Label,node,[Program.Operand.new(endof_clause)])
emit(Constants.ByteCode.Pop,node)
optionCount+=1
option_count+=1
emit(Constants.ByteCode.ShowOptions,node)
emit(Constants.ByteCode.Jump,node)
optionCount = 0
option_count = 0
for option in shortcutGroup.options:
emit(Constants.ByteCode.Label,node,[Program.Operand.new(labels[optionCount])])
for option in shortcut_group.options:
emit(Constants.ByteCode.Label,node,[Program.Operand.new(labels[option_count])])
if option.node != null :
generate_block(node,option.node.statements)
emit(Constants.ByteCode.JumpTo,node,[Program.Operand.new(end)])
optionCount+=1
emit(Constants.ByteCode.Jump_to,node,[Program.Operand.new(end)])
option_count+=1
#end of option group
emit(Constants.ByteCode.Label,node,[Program.Operand.new(end)])
@ -323,10 +323,10 @@ func generate_if(node,if_statement):
if clause.expression!=null:
generate_expression(node,clause.expression)
emit(Constants.ByteCode.JumpIfFalse,node,[Program.Operand.new(end_clause)])
emit(Constants.ByteCode.Jump_if_false,node,[Program.Operand.new(end_clause)])
generate_block(node,clause.statements)
emit(Constants.ByteCode.JumpTo,node,[Program.Operand.new(endif)])
emit(Constants.ByteCode.Jump_to,node,[Program.Operand.new(endif)])
if clause.expression!=null:
emit(Constants.ByteCode.Label,node,[Program.Operand.new(end_clause)])
@ -347,23 +347,23 @@ func generate_option(node,option):
#jump to another node
emit(Constants.ByteCode.RunNode,node,[Program.Operand.new(destination)])
else :
var lineID : String = ''#tags not supported TODO: ADD TAG SUPPORT
var stringID = register_string(option.label,node.nodeName,lineID,option.lineNumber,[])
var line_iD : String = ''#tags not supported TODO: ADD TAG SUPPORT
var string_iD = register_string(option.label,node.node_name,line_iD,option.line_number,[])
emit(Constants.ByteCode.AddOption,node,[Program.Operand.new(stringID),Program.Operand.new(destination)])
emit(Constants.ByteCode.AddOption,node,[Program.Operand.new(string_iD),Program.Operand.new(destination)])
#compile instructions for assigning values
func generate_assignment(node,assignment):
# print('generating assign')
#assignment
if assignment.operation == Constants.TokenType.EqualToOrAssign:
if assignment.operation == Constants.TokenType.Equal_to_or_assign:
#evaluate the expression to a value for the stack
generate_expression(node,assignment.value)
else :
#this is combined op
#get value of var
emit(Constants.ByteCode.PushVariable,node,[assignment.destination])
emit(Constants.ByteCode.Push_variable,node,[assignment.destination])
#evaluate the expression and push value to stack
generate_expression(node,assignment.value)
@ -371,16 +371,16 @@ func generate_assignment(node,assignment):
#stack contains oldvalue and result
match assignment.operation:
Constants.TokenType.AddAssign:
Constants.TokenType.Add_assign:
emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.Add))])
Constants.TokenType.MinusAssign:
Constants.TokenType.Minus_assign:
emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.Minus))])
Constants.TokenType.MultiplyAssign:
Constants.TokenType.Multiply_assign:
emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.MultiplyAssign))])
Constants.TokenType.DivideAssign:
Constants.TokenType.Divide_assign:
emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.DivideAssign))])
_:
@ -388,7 +388,7 @@ func generate_assignment(node,assignment):
#stack contains destination value
#store the top of the stack in variable
emit(Constants.ByteCode.StoreVariable,node,[Program.Operand.new(assignment.destination)])
emit(Constants.ByteCode.Store_variable,node,[Program.Operand.new(assignment.destination)])
#clean stack
emit(Constants.ByteCode.Pop,node)
@ -399,9 +399,9 @@ func generate_expression(node,expression):
# print('generating expression')
#expression = value || func call
match expression.type:
Constants.ExpressionType.Value:
Constants.Expression_type.Value:
generate_value(node,expression.value)
Constants.ExpressionType.FunctionCall:
Constants.Expression_type.Function_call:
#eval all parameters
for param in expression.params:
generate_expression(node,param)
@ -423,7 +423,7 @@ func generate_value(node,value):
emit(Constants.ByteCode.PushNumber,node,[Program.Operand.new(value.value.as_number())])
Constants.ValueType.Str:
var id : String = register_string(value.value.as_string(),
node.nodeName,'',value.lineNumber,[])
node.node_name,'',value.line_number,[])
emit(Constants.ByteCode.PushString,node,[Program.Operand.new(id)])
Constants.ValueType.Boolean:
emit(Constants.ByteCode.PushBool,node,[Program.Operand.new(value.value.as_bool())])
@ -434,27 +434,26 @@ func generate_value(node,value):
_:
printerr('Unrecognized valuenode type: %s' % value.value.type)
#get the error flags
func get_errors()->int:
return _errors
#get the last error code reported
func get_last_error()->int:
return _lastError
return _last_error
func clear_errors()->void:
_errors = NO_ERROR
_lastError = NO_ERROR
_last_error = NO_ERROR
func emit_error(error : int)->void:
_lastError = error
_errors |= _lastError
_last_error = error
_errors |= _last_error
static func print_tokens(tokens:Array=[]):
var list : PoolStringArray = []
list.append('\n')
for token in tokens:
list.append('%s (%s line %s)\n'%[Constants.token_type_name(token.type),token.value,token.lineNumber])
list.append('%s (%s line %s)\n'%[Constants.token_type_name(token.type),token.value,token.line_number])
print('TOKENS:')
print(list.join(''))

View file

@ -188,20 +188,20 @@ func tokenize(text:String)->Array:
var lines : PoolStringArray = text.split(LINE_SEPARATOR)
lines.append('')
var lineNumber : int = 1
var line_number : int = 1
for line in lines:
tokens+=tokenize_line(line,lineNumber)
lineNumber+=1
tokens+=tokenize_line(line,line_number)
line_number+=1
var endOfInput : Token = Token.new(Constants.TokenType.EndOfInput,_currentState,lineNumber,0)
var endOfInput : Token = Token.new(Constants.TokenType.EndOfInput,_currentState,line_number,0)
tokens.append(endOfInput)
# print(tokens)
return tokens
func tokenize_line(line:String, lineNumber : int)->Array:
func tokenize_line(line:String, line_number : int)->Array:
var tokenStack : Array = []
var freshLine = line.replace('\t',' ').replace('\r','')
@ -214,7 +214,7 @@ func tokenize_line(line:String, lineNumber : int)->Array:
#we add an indenation token to record indent level
_indentStack.push_front(IntBoolPair.new(indentation,true))
var indent : Token = Token.new(Constants.TokenType.Indent,_currentState,lineNumber,prevIndentation.key)
var indent : Token = Token.new(Constants.TokenType.Indent,_currentState,line_number,prevIndentation.key)
indent.value = '%*s' % [indentation - prevIndentation.key,'']
_shouldTrackIndent = false
@ -226,7 +226,7 @@ func tokenize_line(line:String, lineNumber : int)->Array:
while indentation < _indentStack.front().key:
var top : IntBoolPair = _indentStack.pop_front()
if top.value:
var deIndent : Token = Token.new(Constants.TokenType.Dedent,_currentState,lineNumber,0)
var deIndent : Token = Token.new(Constants.TokenType.Dedent,_currentState,line_number,0)
tokenStack.push_front(deIndent)
@ -288,7 +288,7 @@ func tokenize_line(line:String, lineNumber : int)->Array:
tokenText = tokenText.replace('\\\\', '\\')
tokenText = tokenText.replace('\\\'','\'')
var token : Token = Token.new(rule.tokenType,_currentState,lineNumber,column,tokenText)
var token : Token = Token.new(rule.tokenType,_currentState,line_number,column,tokenText)
token.delimitsText = rule.delimitsText
tokenStack.push_front(token)
@ -296,7 +296,7 @@ func tokenize_line(line:String, lineNumber : int)->Array:
if rule.enterState != null && rule.enterState.length() > 0:
if !_states.has(rule.enterState):
printerr('State[%s] not known - line(%s) col(%s)'%[rule.enterState,lineNumber,column])
printerr('State[%s] not known - line(%s) col(%s)'%[rule.enterState,line_number,column])
return []
enter_state(_states[rule.enterState])
@ -310,7 +310,7 @@ func tokenize_line(line:String, lineNumber : int)->Array:
if !matched:
# TODO: Send out some helpful messages
printerr('expectedTokens [%s] - line(%s) col(%s)'%['refineErrors.Lexer.tokenize_line',lineNumber,column])
printerr('expectedTokens [%s] - line(%s) col(%s)'%['refineErrors.Lexer.tokenize_line',line_number,column])
return []
var lastWhiteSpace : RegExMatch = whitespace.search(line,column)
@ -342,7 +342,7 @@ class Token:
var type : int
var value : String
var lineNumber : int
var line_number : int
var column : int
var text : String
@ -350,15 +350,15 @@ class Token:
var paramCount : int
var lexerState : String
func _init(type:int,state: LexerState, lineNumber:int = -1,column:int = -1,value:String =''):
func _init(type:int,state: LexerState, line_number:int = -1,column:int = -1,value:String =''):
self.type = type
self.lexerState = state.stateName
self.lineNumber = lineNumber
self.line_number = line_number
self.column = column
self.value = value
func _to_string():
return '%s (%s) at %s:%s (state: %s)' % [Constants.token_type_name(type),value,lineNumber,column,lexerState]
return '%s (%s) at %s:%s (state: %s)' % [Constants.token_type_name(type),value,line_number,column,lexerState]
class LexerState:

View file

@ -56,20 +56,20 @@ func tokens():
class ParseNode:
var parent
var lineNumber = -1
var line_number = -1
var tags = []
func _init(parent, parser):
self.parent = parent
var tokens = parser.tokens() as Array
if tokens.size() > 0:
lineNumber = tokens.front().lineNumber
line_number = tokens.front().line_number
else:
lineNumber = -1
line_number = -1
tags = []
func tree_string(indent_level):
return 'NotImplemented'
return 'Not_implemented'
func tags_to_string(indent_level):
return '%s' % 'TAGS<tags_to_string>NOTIMPLEMENTED'
@ -93,7 +93,7 @@ class WolNode extends ParseNode:
var name = ''
var source = ''
var editorNodeTags = []
var editor_node_tags = []
var statements = []
func _init(name, parent, parser).(parent, parser):
@ -140,7 +140,7 @@ class Statement extends ParseNode:
elif Assignment.can_parse(parser):
assignment = Assignment.new(self, parser)
type = Type.AssignmentStatement
type = Type.Assignment_statement
elif ShortcutOptionGroup.can_parse(parser):
shortcut_option_group = ShortcutOptionGroup.new(self, parser)
@ -175,7 +175,7 @@ class Statement extends ParseNode:
info.append(block.tree_string(indent_level))
Type.IfStatement:
info.append(if_statement.tree_string(indent_level))
Type.AssignmentStatement:
Type.Assignment_statement:
info.append(assignment.tree_string(indent_level))
Type.OptionStatement:
info.append(option_statement.tree_string(indent_level))
@ -194,7 +194,7 @@ class CustomCommand extends ParseNode:
enum Type {
Expression,
ClientCommand
Client_command
}
var type = -1
@ -215,21 +215,21 @@ class CustomCommand extends ParseNode:
#if first token is identifier and second is leftt parenthesis
#evaluate as function
if (command_tokens.size() > 1 && command_tokens[0].type == Constants.TokenType.Identifier
&& command_tokens[1].type == Constants.TokenType.LeftParen):
&& command_tokens[1].type == Constants.TokenType.Left_paren):
var p = get_script().new(command_tokens, parser.library)
var expression = ExpressionNode.parse(self, p)
var expression = Expression_node.parse(self, p)
type = Type.Expression
self.expression = expression
else:
#otherwise evaluuate command
type = Type.ClientCommand
type = Type.Client_command
self.client_command = command_tokens[0].value
func tree_string(indent_level):
match type:
Type.Expression:
return tab(indent_level,'Expression: %s'% expression.tree_string(indent_level+1))
Type.ClientCommand:
Type.Client_command:
return tab(indent_level,'Command: %s' % client_command)
return ''
@ -246,10 +246,10 @@ class ShortcutOptionGroup extends ParseNode:
# expect one otherwise invalid
var index = 1
options.append(ShortCutOption.new(index, self, parser))
options.append(Short_cut_option.new(index, self, parser))
index += 1
while parser.next_symbol_is([Constants.TokenType.ShortcutOption]):
options.append(ShortCutOption.new(index, self, parser))
options.append(Short_cut_option.new(index, self, parser))
index += 1
func tree_string(indent_level):
@ -267,7 +267,7 @@ class ShortcutOptionGroup extends ParseNode:
static func can_parse(parser):
return parser.next_symbol_is([Constants.TokenType.ShortcutOption])
class ShortCutOption extends ParseNode:
class Short_cut_option extends ParseNode:
var label = ''
var condition
var node
@ -285,7 +285,7 @@ class ShortCutOption extends ParseNode:
if parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.IfToken]):
parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.IfToken])
condition = ExpressionNode.parse(self, parser)
condition = Expression_node.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand])
elif parser.next_symbol_is([Constants.TokenType.TagMarker]):
@ -397,14 +397,14 @@ class IfStatement extends ParseNode:
parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.IfToken])
prime.expression = ExpressionNode.parse(self, parser)
prime.expression = Expression_node.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand])
#read statements until 'endif' or 'else' or 'else if'
var statements = []#statement
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.EndIf]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseToken]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseIf]):
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.End_if]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_token]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_if]):
statements.append(Statement.new(self, parser))
@ -416,20 +416,20 @@ class IfStatement extends ParseNode:
clauses.append(prime)
#handle all else if
while parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseIf]):
while parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_if]):
var clause_elif = Clause.new()
#parse condition syntax
parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.ElseIf])
clause_elif.expression = ExpressionNode.parse(self, parser)
parser.expect_symbol([Constants.TokenType.Else_if])
clause_elif.expression = Expression_node.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand])
var elif_statements = []#statement
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.EndIf]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseToken]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseIf]):
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.End_if]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_token]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_if]):
elif_statements.append(Statement.new(self, parser))
@ -442,21 +442,21 @@ class IfStatement extends ParseNode:
#handle else if exists
if (parser.next_symbols_are([Constants.TokenType.BeginCommand,
Constants.TokenType.ElseToken, Constants.TokenType.EndCommand])):
Constants.TokenType.Else_token, Constants.TokenType.EndCommand])):
#expect no expression - just <<else>>
parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.ElseToken])
parser.expect_symbol([Constants.TokenType.Else_token])
parser.expect_symbol([Constants.TokenType.EndCommand])
#parse until hit endif
var clauseElse = Clause.new()
var elStatements = []#statement
while !parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.EndIf]):
elStatements.append(Statement.new(self, parser))
var clause_else = Clause.new()
var el_statements = []#statement
while !parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.End_if]):
el_statements.append(Statement.new(self, parser))
clauseElse.statements = elStatements
clauses.append(clauseElse)
clause_else.statements = el_statements
clauses.append(clause_else)
#ignore dedent
while parser.next_symbol_is([Constants.TokenType.Dedent]):
@ -464,7 +464,7 @@ class IfStatement extends ParseNode:
#finish
parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.EndIf])
parser.expect_symbol([Constants.TokenType.End_if])
parser.expect_symbol([Constants.TokenType.EndCommand])
@ -488,7 +488,7 @@ class IfStatement extends ParseNode:
return parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.IfToken])
pass
class ValueNode extends ParseNode:
class Value_node extends ParseNode:
const Value = preload('res://addons/Wol/core/value.gd')
const Lexer = preload('res://addons/Wol/core/compiler/lexer.gd')
var value
@ -508,15 +508,15 @@ class ValueNode extends ParseNode:
value = Value.new(float(token.value))
Constants.TokenType.Str:
value = Value.new(token.value)
Constants.TokenType.FalseToken:
Constants.TokenType.False_token:
value = Value.new(false)
Constants.TokenType.TrueToken:
Constants.TokenType.True_token:
value = Value.new(true)
Constants.TokenType.Variable:
value = Value.new(null)
value.type = Constants.ValueType.Variable
value.type = Constants.Value_type.Variable
value.variable = token.value
Constants.TokenType.NullToken:
Constants.TokenType.Null_token:
value = Value.new(null)
_:
printerr('%s, Invalid token type' % token.name)
@ -529,33 +529,33 @@ class ValueNode extends ParseNode:
# math (1 + 2 - 5 * 3 / 10 % 2)
# Identifiers
# Values
class ExpressionNode extends ParseNode:
class Expression_node extends ParseNode:
var type
var value
var function
var params = []#ExpressionNode
var params = []#Expression_node
func _init(parent, parser, value, function = '', params = []).(parent, parser):
#no function - means value
if value != null:
self.type = Constants.ExpressionType.Value
self.type = Constants.Expression_type.Value
self.value = value
else:#function
self.type = Constants.ExpressionType.FunctionCall
self.type = Constants.Expression_type.Function_call
self.function = function
self.params = params
func tree_string(indent_level):
var info = []
match type:
Constants.ExpressionType.Value:
Constants.Expression_type.Value:
return value.tree_string(indent_level)
Constants.ExpressionType.FunctionCall:
Constants.Expression_type.Function_call:
info.append(tab(indent_level,'Func[%s - params(%s)]:{'%[function, params.size()]))
for param in params:
#print('----> %s paramSize:%s'%[(function) , params.size()])
#print('----> %s param_size:%s'%[(function) , params.size()])
info.append(param.tree_string(indent_level+1))
info.append(tab(indent_level,'}'))
@ -566,68 +566,68 @@ class ExpressionNode extends ParseNode:
#build a tree of expressions
static func parse(parent, parser):
var rpn = []
var opStack = []
var op_stack = []
#track params
var funcStack = []
var func_stack = []
var validTypes = [
var valid_types = [
Constants.TokenType.Number,
Constants.TokenType.Variable,
Constants.TokenType.Str,
Constants.TokenType.LeftParen,
Constants.TokenType.RightParen,
Constants.TokenType.Left_paren,
Constants.TokenType.Right_paren,
Constants.TokenType.Identifier,
Constants.TokenType.Comma,
Constants.TokenType.TrueToken,
Constants.TokenType.FalseToken,
Constants.TokenType.NullToken
Constants.TokenType.True_token,
Constants.TokenType.False_token,
Constants.TokenType.Null_token
]
validTypes += Operator.op_types()
validTypes.invert()
valid_types += Operator.op_types()
valid_types.invert()
var last
#read expression content
while parser.tokens().size() > 0 && parser.next_symbol_is(validTypes):
var next = parser.expect_symbol(validTypes)
while parser.tokens().size() > 0 && parser.next_symbol_is(valid_types):
var next = parser.expect_symbol(valid_types)
if next.type == Constants.TokenType.Variable \
or next.type == Constants.TokenType.Number \
or next.type == Constants.TokenType.Str \
or next.type == Constants.TokenType.FalseToken \
or next.type == Constants.TokenType.TrueToken \
or next.type == Constants.TokenType.NullToken:
or next.type == Constants.TokenType.False_token \
or next.type == Constants.TokenType.True_token \
or next.type == Constants.TokenType.Null_token:
#output primitives
rpn.append(next)
elif next.type == Constants.TokenType.Identifier:
opStack.push_back(next)
funcStack.push_back(next)
op_stack.push_back(next)
func_stack.push_back(next)
#next token is parent - left
next = parser.expect_symbol([Constants.TokenType.LeftParen])
opStack.push_back(next)
next = parser.expect_symbol([Constants.TokenType.Left_paren])
op_stack.push_back(next)
elif next.type == Constants.TokenType.Comma:
#resolve sub expression before moving on
while opStack.back().type != Constants.TokenType.LeftParen:
var p = opStack.pop_back()
while op_stack.back().type != Constants.TokenType.Left_paren:
var p = op_stack.pop_back()
if p == null:
printerr('unbalanced parenthesis %s ' % next.name)
break
rpn.append(p)
#next token in opStack left paren
#next token in op_stack left paren
# 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.Right_paren,
Constants.TokenType.Comma]):
printerr('Expected Expression : %s' % parser.tokens().front().name)
#find the closest function on stack
#increment parameters
funcStack.back().paramCount+=1
func_stack.back().param_count+=1
elif Operator.is_op(next.type):
#this is an operator
@ -643,10 +643,10 @@ class ExpressionNode extends ParseNode:
if next.type == Constants.TokenType.Minus:
if last == null \
or last.type == Constants.TokenType.LeftParen \
or last.type == Constants.TokenType.Left_paren \
or Operator.is_op(last.type):
#unary minus
next.type = Constants.TokenType.UnaryMinus
next.type = Constants.TokenType.Unary_minus
#cannot assign inside expression
# x = a is the same as x == a
@ -655,42 +655,42 @@ class ExpressionNode extends ParseNode:
#operator precedence
while (ExpressionNode.is_apply_precedence(next.type, opStack)):
var op = opStack.pop_back()
while (Expression_node.is_apply_precedence(next.type, op_stack)):
var op = op_stack.pop_back()
rpn.append(op)
opStack.push_back(next)
op_stack.push_back(next)
elif next.type == Constants.TokenType.LeftParen:
elif next.type == Constants.TokenType.Left_paren:
#entered parenthesis sub expression
opStack.push_back(next)
elif next.type == Constants.TokenType.RightParen:
op_stack.push_back(next)
elif next.type == Constants.TokenType.Right_paren:
#leaving sub expression
# resolve order of operations
while opStack.back().type != Constants.TokenType.LeftParen:
rpn.append(opStack.pop_back())
if opStack.back() == null:
printerr('Unbalanced parenthasis #RightParen. Parser.ExpressionNode')
while op_stack.back().type != Constants.TokenType.Left_paren:
rpn.append(op_stack.pop_back())
if op_stack.back() == null:
printerr('Unbalanced parenthasis #Right_paren. Parser.Expression_node')
opStack.pop_back()
if opStack.back().type == Constants.TokenType.Identifier:
op_stack.pop_back()
if op_stack.back().type == Constants.TokenType.Identifier:
#function call
#last token == left paren this == no params
#else
#we have more than 1 param
if last.type != Constants.TokenType.LeftParen:
funcStack.back().paramCount+=1
if last.type != Constants.TokenType.Left_paren:
func_stack.back().param_count+=1
rpn.append(opStack.pop_back())
funcStack.pop_back()
rpn.append(op_stack.pop_back())
func_stack.pop_back()
#record last token used
last = next
#no more tokens : pop operators to output
while opStack.size() > 0:
rpn.append(opStack.pop_back())
while op_stack.size() > 0:
rpn.append(op_stack.pop_back())
#if rpn is empty then this is not expression
if rpn.size() == 0:
@ -698,7 +698,7 @@ class ExpressionNode extends ParseNode:
#build expression tree
var first = rpn.front()
var evalStack = []#ExpressionNode
var eval_stack = []#Expression_node
while rpn.size() > 0:
@ -707,50 +707,50 @@ class ExpressionNode extends ParseNode:
#operation
var info = Operator.op_info(next.type)
if evalStack.size() < info.arguments:
printerr('Error parsing : Not enough arguments for %s [ got %s expected - was %s]'%[Constants.token_type_name(next.type), evalStack.size(), info.arguments])
if eval_stack.size() < info.arguments:
printerr('Error parsing : Not enough arguments for %s [ got %s expected - was %s]'%[Constants.token_type_name(next.type), eval_stack.size(), info.arguments])
var params = []#ExpressionNode
var params = []#Expression_node
for i in range(info.arguments):
params.append(evalStack.pop_back())
params.append(eval_stack.pop_back())
params.invert()
var function = get_func_name(next.type)
var expression = ExpressionNode.new(parent, parser, null, function, params)
var expression = Expression_node.new(parent, parser, null, function, params)
evalStack.append(expression)
eval_stack.append(expression)
elif next.type == Constants.TokenType.Identifier:
#function call
var function = next.value
var params = []#ExpressionNode
for i in range(next.paramCount):
var params = []#Expression_node
for i in range(next.param_count):
params.append(evalStack.pop_back())
params.append(eval_stack.pop_back())
params.invert()
var expression = ExpressionNode.new(parent, parser, null, function, params)
var expression = Expression_node.new(parent, parser, null, function, params)
evalStack.append(expression)
eval_stack.append(expression)
else: #raw value
var value = ValueNode.new(parent, parser, next)
var expression = ExpressionNode.new(parent, parser, value)
evalStack.append(expression)
var value = Value_node.new(parent, parser, next)
var expression = Expression_node.new(parent, parser, value)
eval_stack.append(expression)
#we should have a single root expression left
#if more then we failed ---- NANI
if evalStack.size() != 1:
if eval_stack.size() != 1:
printerr('[%s] Error parsing expression (stack did not reduce correctly )' % first.name)
return evalStack.pop_back()
return eval_stack.pop_back()
static func get_func_name(type):
var string = ''
@ -760,27 +760,27 @@ class ExpressionNode extends ParseNode:
return key
return string
static func is_apply_precedence(type, operatorStack):
if operatorStack.size() == 0:
static func is_apply_precedence(type, operator_stack):
if operator_stack.size() == 0:
return false
if not Operator.is_op(type):
printerr('Unable to parse expression!')
var second = operatorStack.back().type
var second = operator_stack.back().type
if not Operator.is_op(second):
return false
var firstInfo = Operator.op_info(type)
var secondInfo = Operator.op_info(second)
var first_info = Operator.op_info(type)
var second_info = Operator.op_info(second)
if (firstInfo.associativity == Associativity.Left &&
firstInfo.precedence <= secondInfo.precedence):
if (first_info.associativity == Associativity.Left &&
first_info.precedence <= second_info.precedence):
return true
if (firstInfo.associativity == Associativity.Right &&
firstInfo.precedence < secondInfo.precedence):
if (first_info.associativity == Associativity.Right &&
first_info.precedence < second_info.precedence):
return true
return false
@ -796,7 +796,7 @@ class Assignment extends ParseNode:
parser.expect_symbol([Constants.TokenType.Set])
destination = parser.expect_symbol([Constants.TokenType.Variable]).value
operation = parser.expect_symbol(Assignment.valid_ops()).type
value = ExpressionNode.parse(self, parser)
value = Expression_node.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand])
func tree_string(indent_level):
@ -817,26 +817,26 @@ class Assignment extends ParseNode:
static func valid_ops():
return [
Constants.TokenType.EqualToOrAssign,
Constants.TokenType.AddAssign,
Constants.TokenType.MinusAssign,
Constants.TokenType.DivideAssign,
Constants.TokenType.MultiplyAssign
Constants.TokenType.Add_assign,
Constants.TokenType.Minus_assign,
Constants.TokenType.Divide_assign,
Constants.TokenType.Multiply_assign
]
class Operator extends ParseNode:
var opType
var op_type
func _init(parent, parser, opType=null).(parent, parser):
func _init(parent, parser, op_type=null).(parent, parser):
if opType == null :
self.opType = parser.expect_symbol(Operator.op_types()).type
if op_type == null :
self.op_type = parser.expect_symbol(Operator.op_types()).type
else:
self.opType = opType
self.op_type = op_type
func tree_string(indent_level):
var info = []
info.append(tab(indent_level, opType))
info.append(tab(indent_level, op_type))
return info.join('')
static func op_info(op):
@ -848,22 +848,22 @@ class Operator extends ParseNode:
var TokenType = Constants.TokenType
match op:
TokenType.Not, TokenType.UnaryMinus:
return OperatorInfo.new(Associativity.Right, 30, 1)
TokenType.Not, TokenType.Unary_minus:
return Operator_info.new(Associativity.Right, 30, 1)
TokenType.Multiply, TokenType.Divide, TokenType.Modulo:
return OperatorInfo.new(Associativity.Left, 20, 2)
return Operator_info.new(Associativity.Left, 20, 2)
TokenType.Add, TokenType.Minus:
return OperatorInfo.new(Associativity.Left, 15, 2)
return Operator_info.new(Associativity.Left, 15, 2)
TokenType.GreaterThan, TokenType.LessThan, TokenType.GreaterThanOrEqualTo, TokenType.LessThanOrEqualTo:
return OperatorInfo.new(Associativity.Left, 10, 2)
return Operator_info.new(Associativity.Left, 10, 2)
TokenType.EqualTo, TokenType.EqualToOrAssign, TokenType.NotEqualTo:
return OperatorInfo.new(Associativity.Left, 5, 2)
return Operator_info.new(Associativity.Left, 5, 2)
TokenType.And:
return OperatorInfo.new(Associativity.Left, 4, 2)
return Operator_info.new(Associativity.Left, 4, 2)
TokenType.Or:
return OperatorInfo.new(Associativity.Left, 3, 2)
return Operator_info.new(Associativity.Left, 3, 2)
TokenType.Xor:
return OperatorInfo.new(Associativity.Left, 2, 2)
return Operator_info.new(Associativity.Left, 2, 2)
_:
printerr('Unknown operator: %s' % op.name)
return null
@ -874,7 +874,7 @@ class Operator extends ParseNode:
static func op_types():
return [
Constants.TokenType.Not,
Constants.TokenType.UnaryMinus,
Constants.TokenType.Unary_minus,
Constants.TokenType.Add,
Constants.TokenType.Minus,
@ -897,7 +897,7 @@ class Operator extends ParseNode:
]
class OperatorInfo:
class Operator_info:
var associativity
var precedence = -1
var arguments = -1