went through all warnings and corrected them
This commit is contained in:
parent
cda5fe8406
commit
7822c7e6b0
|
@ -3,10 +3,15 @@ extends Node
|
||||||
class_name Wol
|
class_name Wol
|
||||||
|
|
||||||
signal node_started(node)
|
signal node_started(node)
|
||||||
|
signal node_finished(node)
|
||||||
|
|
||||||
|
# NOTE: Warning is ignored because they get call_deferred
|
||||||
|
# warning-ignore:unused_signal
|
||||||
signal line(line)
|
signal line(line)
|
||||||
|
# warning-ignore:unused_signal
|
||||||
signal options(options)
|
signal options(options)
|
||||||
|
# warning-ignore:unused_signal
|
||||||
signal command(command)
|
signal command(command)
|
||||||
signal node_completed(node)
|
|
||||||
|
|
||||||
signal started
|
signal started
|
||||||
signal finished
|
signal finished
|
||||||
|
@ -62,14 +67,12 @@ func init_dialogue():
|
||||||
dialogue.set_program(program)
|
dialogue.set_program(program)
|
||||||
|
|
||||||
func set_path(_path):
|
func set_path(_path):
|
||||||
if not Engine.editor_hint:
|
|
||||||
var file = File.new()
|
|
||||||
file.open(_path, File.READ)
|
|
||||||
var source = file.get_as_text()
|
|
||||||
file.close()
|
|
||||||
program = WolCompiler.compile_string(source, _path)
|
|
||||||
path = _path
|
path = _path
|
||||||
|
|
||||||
|
if not Engine.editor_hint:
|
||||||
|
var compiler = WolCompiler.new(path)
|
||||||
|
program = compiler.compile()
|
||||||
|
|
||||||
func _handle_line(line):
|
func _handle_line(line):
|
||||||
call_deferred('emit_signal', 'line', line)
|
call_deferred('emit_signal', 'line', line)
|
||||||
if auto_show_options \
|
if auto_show_options \
|
||||||
|
@ -103,7 +106,7 @@ func _handle_node_start(node):
|
||||||
dialogue._visitedNodeCount[node] += 1
|
dialogue._visitedNodeCount[node] += 1
|
||||||
|
|
||||||
func _handle_node_complete(node):
|
func _handle_node_complete(node):
|
||||||
emit_signal('node_completed', node)
|
emit_signal('node_finished', node)
|
||||||
return Constants.HandlerState.ContinueExecution
|
return Constants.HandlerState.ContinueExecution
|
||||||
|
|
||||||
func select_option(id):
|
func select_option(id):
|
||||||
|
|
|
@ -4,158 +4,152 @@ class_name Compiler
|
||||||
const Constants = preload('res://addons/Wol/core/constants.gd')
|
const Constants = preload('res://addons/Wol/core/constants.gd')
|
||||||
const Lexer = preload('res://addons/Wol/core/compiler/lexer.gd')
|
const Lexer = preload('res://addons/Wol/core/compiler/lexer.gd')
|
||||||
const Program = preload('res://addons/Wol/core/program.gd')
|
const Program = preload('res://addons/Wol/core/program.gd')
|
||||||
|
const Parser = preload('res://addons/Wol/core/compiler/parser.gd')
|
||||||
|
|
||||||
#patterns
|
const INVALID_TITLE = '[\\[<>\\]{}\\|:\\s#\\$]'
|
||||||
const INVALIDTITLENAME = '[\\[<>\\]{}\\|:\\s#\\$]'
|
|
||||||
|
|
||||||
#ERROR Codes
|
|
||||||
const NO_ERROR = 0x00
|
const NO_ERROR = 0x00
|
||||||
const LEXER_FAILURE = 0x01
|
const LEXER_FAILURE = 0x01
|
||||||
const PARSER_FAILURE = 0x02
|
const PARSER_FAILURE = 0x02
|
||||||
const INVALID_HEADER = 0x04
|
const INVALID_HEADER = 0x04
|
||||||
const DUPLICATE_NODES_IN_PROGRAM = 0x08
|
|
||||||
const ERR_COMPILATION_FAILED = 0x10
|
const ERR_COMPILATION_FAILED = 0x10
|
||||||
|
|
||||||
var _errors : int
|
var source = ''
|
||||||
var _last_error : int
|
var filename = ''
|
||||||
|
|
||||||
#-----Class vars
|
var _current_node
|
||||||
var _current_node : Program.WolNode
|
var _contains_implicit_string_tags = false
|
||||||
var _raw_text : bool
|
var _label_count = 0
|
||||||
var _file_name : String
|
|
||||||
var _contains_implicit_string_tags : bool
|
|
||||||
var _label_count : int = 0
|
|
||||||
|
|
||||||
#<String, Program.Line>
|
var _string_table = {}
|
||||||
var _string_table : Dictionary = {}
|
var _string_count = 0
|
||||||
var _string_count : int = 0
|
|
||||||
#<int, Constants.TokenType>
|
|
||||||
var _tokens : Dictionary = {}
|
|
||||||
|
|
||||||
static func compile_string(source: String, filename: String):
|
func _init(_filename, _source = null):
|
||||||
var Parser = load('res://addons/Wol/core/compiler/parser.gd')
|
filename = _filename
|
||||||
var Compiler = load('res://addons/Wol/core/compiler/compiler.gd')
|
|
||||||
|
|
||||||
var compiler = Compiler.new()
|
if not _filename and _source:
|
||||||
compiler._file_name = filename
|
self.source = _source
|
||||||
|
else:
|
||||||
|
var file = File.new()
|
||||||
|
file.open(_filename, File.READ)
|
||||||
|
self.source = file.get_as_text()
|
||||||
|
file.close()
|
||||||
|
|
||||||
#--------------Nodes
|
func compile():
|
||||||
var header_sep : RegEx = RegEx.new()
|
var header_sep = RegEx.new()
|
||||||
|
var header_property = RegEx.new()
|
||||||
header_sep.compile('---(\r\n|\r|\n)')
|
header_sep.compile('---(\r\n|\r|\n)')
|
||||||
var header_property : RegEx = RegEx.new()
|
|
||||||
header_property.compile('(?<field>.*): *(?<value>.*)')
|
header_property.compile('(?<field>.*): *(?<value>.*)')
|
||||||
|
|
||||||
assert(not not header_sep.search(source), 'No headers found')
|
assert(header_sep.search(source), 'No headers found!')
|
||||||
|
|
||||||
var line_number: int = 0
|
var line_number = 0
|
||||||
|
|
||||||
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 parsed_nodes : Array = []
|
var source_lines = source.split('\n', false)
|
||||||
|
for i in range(source_lines.size()):
|
||||||
|
source_lines[i] = source_lines[i].strip_edges(false, true)
|
||||||
|
|
||||||
|
var parsed_nodes = []
|
||||||
|
|
||||||
while line_number < source_lines.size():
|
while line_number < source_lines.size():
|
||||||
|
var title = ''
|
||||||
var title : String
|
var body = ''
|
||||||
var body : String
|
|
||||||
|
|
||||||
#get title
|
# Parse header
|
||||||
while true:
|
while true:
|
||||||
var line : String = source_lines[line_number]
|
var line = source_lines[line_number]
|
||||||
line_number+=1
|
line_number += 1
|
||||||
|
|
||||||
if !line.empty():
|
if not line.empty():
|
||||||
var result = header_property.search(line)
|
var result = header_property.search(line)
|
||||||
if result != null :
|
if result != null:
|
||||||
var field : String = result.get_string('field')
|
var field = result.get_string('field')
|
||||||
var value : String = result.get_string('value')
|
var value = result.get_string('value')
|
||||||
|
|
||||||
if field == 'title':
|
if field == 'title':
|
||||||
assert(not ' ' in value, 'No space allowed in title "%s", correct to "%s"' % [value, value.replace(' ','')])
|
var regex = RegEx.new()
|
||||||
title = value
|
regex.compile(INVALID_TITLE)
|
||||||
|
assert(not regex.search(value), 'Invalid characters in title "%s", correct to "%s"' % [value, regex.sub(value, '', true)])
|
||||||
|
|
||||||
if(line_number >= source_lines.size() || source_lines[line_number] == '---'):
|
title = value
|
||||||
|
# TODO: Implement position, color and tags
|
||||||
|
|
||||||
|
if line_number >= source_lines.size() or line == '---':
|
||||||
break
|
break
|
||||||
|
|
||||||
|
line_number += 1
|
||||||
line_number+=1
|
|
||||||
|
|
||||||
#past header
|
# past header
|
||||||
var body_lines : PoolStringArray = []
|
var body_lines = []
|
||||||
|
|
||||||
while line_number < source_lines.size() and source_lines[line_number]!='===':
|
while line_number < source_lines.size() and source_lines[line_number] != '===':
|
||||||
body_lines.append(source_lines[line_number])
|
body_lines.append(source_lines[line_number])
|
||||||
line_number+=1
|
line_number += 1
|
||||||
|
|
||||||
line_number+=1
|
line_number += 1
|
||||||
|
|
||||||
body = body_lines.join('\n')
|
body = PoolStringArray(body_lines).join('\n')
|
||||||
var lexer = Lexer.new()
|
|
||||||
var tokens = lexer.tokenize(body, title, filename)
|
|
||||||
|
|
||||||
var parser = Parser.new(tokens, title)
|
var lexer = Lexer.new(filename, title, body)
|
||||||
|
var tokens = lexer.tokenize()
|
||||||
|
|
||||||
|
var parser = Parser.new(title, tokens)
|
||||||
var parser_node = parser.parse_node()
|
var parser_node = parser.parse_node()
|
||||||
|
|
||||||
parser_node.name = title
|
parser_node.name = title
|
||||||
|
# parser_node.tags = title
|
||||||
parsed_nodes.append(parser_node)
|
parsed_nodes.append(parser_node)
|
||||||
while line_number < source_lines.size() && source_lines[line_number].empty():
|
|
||||||
line_number+=1
|
|
||||||
|
|
||||||
#--- End parsing nodes---
|
while line_number < source_lines.size() and source_lines[line_number].empty():
|
||||||
|
line_number += 1
|
||||||
|
|
||||||
var program = Program.new()
|
var program = Program.new()
|
||||||
|
|
||||||
#compile nodes
|
|
||||||
for node in parsed_nodes:
|
for node in parsed_nodes:
|
||||||
compiler.compile_node(program, node)
|
compile_node(program, node)
|
||||||
|
|
||||||
for key in compiler._string_table:
|
for key in _string_table:
|
||||||
program.strings[key] = compiler._string_table[key]
|
program.strings[key] = _string_table[key]
|
||||||
|
|
||||||
return program
|
return program
|
||||||
|
|
||||||
func compile_node(program, parsed_node):
|
func compile_node(program, parsed_node):
|
||||||
if program.nodes.has(parsed_node.name):
|
assert(not program.nodes.has(parsed_node.name), 'Duplicate node in program: %s' % parsed_node.name)
|
||||||
emit_error(DUPLICATE_NODES_IN_PROGRAM)
|
|
||||||
printerr('Duplicate node in program: %s' % parsed_node.name)
|
var node_compiled = Program.WolNode.new()
|
||||||
|
|
||||||
|
node_compiled.name = parsed_node.name
|
||||||
|
node_compiled.tags = parsed_node.tags
|
||||||
|
|
||||||
|
if parsed_node.source != null and not parsed_node.source.empty():
|
||||||
|
node_compiled.source_id = register_string(
|
||||||
|
parsed_node.source,
|
||||||
|
parsed_node.name,
|
||||||
|
'line:' + parsed_node.name,
|
||||||
|
0,
|
||||||
|
[]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
var node_compiled = Program.WolNode.new()
|
var start_label = register_label()
|
||||||
|
emit(Constants.ByteCode.Label,node_compiled,[Program.Operand.new(start_label)])
|
||||||
|
|
||||||
node_compiled.name = parsed_node.name
|
for statement in parsed_node.statements:
|
||||||
node_compiled.tags = parsed_node.tags
|
generate_statement(node_compiled, statement)
|
||||||
|
|
||||||
|
var dangling_options = false
|
||||||
|
for instruction in node_compiled.instructions:
|
||||||
|
if instruction.operation == Constants.ByteCode.AddOption:
|
||||||
|
dangling_options = true
|
||||||
|
if instruction.operation == Constants.ByteCode.ShowOptions:
|
||||||
|
dangling_options = false
|
||||||
|
|
||||||
#raw text
|
if dangling_options:
|
||||||
if parsed_node.source != null && !parsed_node.source.empty():
|
emit(Constants.ByteCode.ShowOptions, node_compiled)
|
||||||
node_compiled.source_id = register_string(parsed_node.source,parsed_node.name,
|
emit(Constants.ByteCode.RunNode, node_compiled)
|
||||||
'line:'+parsed_node.name, 0, [])
|
|
||||||
else:
|
else:
|
||||||
#compile node
|
emit(Constants.ByteCode.Stop, node_compiled)
|
||||||
var start_label : String = register_label()
|
|
||||||
emit(Constants.ByteCode.Label,node_compiled,[Program.Operand.new(start_label)])
|
|
||||||
|
|
||||||
for statement in parsed_node.statements:
|
program.nodes[node_compiled.name] = node_compiled
|
||||||
generate_statement(node_compiled,statement)
|
|
||||||
|
|
||||||
|
|
||||||
#add options
|
|
||||||
#todo: add parser flag
|
|
||||||
|
|
||||||
var dangling_options = false
|
|
||||||
for instruction in node_compiled.instructions :
|
|
||||||
if instruction.operation == Constants.ByteCode.AddOption:
|
|
||||||
dangling_options = true
|
|
||||||
if instruction.operation == Constants.ByteCode.ShowOptions:
|
|
||||||
dangling_options = false
|
|
||||||
|
|
||||||
if dangling_options:
|
|
||||||
emit(Constants.ByteCode.ShowOptions, node_compiled)
|
|
||||||
emit(Constants.ByteCode.RunNode, node_compiled)
|
|
||||||
else:
|
|
||||||
emit(Constants.ByteCode.Stop, node_compiled)
|
|
||||||
|
|
||||||
|
|
||||||
program.nodes[node_compiled.name] = node_compiled
|
|
||||||
|
|
||||||
func register_string(text:String,node_name:String,id:String='',line_number:int=-1,tags:Array=[])->String:
|
func register_string(text:String,node_name:String,id:String='',line_number:int=-1,tags:Array=[])->String:
|
||||||
var line_id_used : String
|
var line_id_used : String
|
||||||
|
@ -163,7 +157,7 @@ func register_string(text:String,node_name:String,id:String='',line_number:int=-
|
||||||
var implicit : bool
|
var implicit : bool
|
||||||
|
|
||||||
if id.empty():
|
if id.empty():
|
||||||
line_id_used = '%s-%s-%d' % [self._file_name,node_name,self._string_count]
|
line_id_used = '%s-%s-%d' % [self.filename,node_name,self._string_count]
|
||||||
self._string_count+=1
|
self._string_count+=1
|
||||||
|
|
||||||
#use this when we generate implicit tags
|
#use this when we generate implicit tags
|
||||||
|
@ -176,7 +170,7 @@ func register_string(text:String,node_name:String,id:String='',line_number:int=-
|
||||||
line_id_used = id
|
line_id_used = id
|
||||||
implicit = false
|
implicit = false
|
||||||
|
|
||||||
var string_info = Program.Line.new(text,node_name,line_number,_file_name,implicit,tags)
|
var string_info = Program.Line.new(text,node_name,line_number,filename,implicit,tags)
|
||||||
#add to string table and return id
|
#add to string table and return id
|
||||||
self._string_table[line_id_used] = string_info
|
self._string_table[line_id_used] = string_info
|
||||||
|
|
||||||
|
@ -202,18 +196,11 @@ func emit(bytecode, node = _current_node, operands = []):
|
||||||
node.labels[instruction.operands[0].value] = node.instructions.size()-1
|
node.labels[instruction.operands[0].value] = node.instructions.size()-1
|
||||||
|
|
||||||
|
|
||||||
func get_string_tokens()->Array:
|
|
||||||
return []
|
|
||||||
|
|
||||||
#compile header
|
|
||||||
func generate_header():
|
func generate_header():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
#compile instructions for statements
|
|
||||||
#this will walk through all child branches
|
|
||||||
#of the parse tree
|
|
||||||
func generate_statement(node,statement):
|
func generate_statement(node,statement):
|
||||||
# print('generating statement')
|
|
||||||
match statement.type:
|
match statement.type:
|
||||||
Constants.StatementTypes.CustomCommand:
|
Constants.StatementTypes.CustomCommand:
|
||||||
generate_custom_command(node,statement.custom_command)
|
generate_custom_command(node,statement.custom_command)
|
||||||
|
@ -230,8 +217,7 @@ func generate_statement(node,statement):
|
||||||
Constants.StatementTypes.Line:
|
Constants.StatementTypes.Line:
|
||||||
generate_line(node,statement,statement.line)
|
generate_line(node,statement,statement.line)
|
||||||
_:
|
_:
|
||||||
emit_error(ERR_COMPILATION_FAILED)
|
assert(false, 'Illegal statement type [%s]. Could not generate code.' % statement.type)
|
||||||
printerr('illegal statement type [%s]- could not generate code' % statement.type)
|
|
||||||
|
|
||||||
#compile instructions for custom commands
|
#compile instructions for custom commands
|
||||||
func generate_custom_command(node,command):
|
func generate_custom_command(node,command):
|
||||||
|
@ -306,7 +292,6 @@ func generate_shortcut_group(node,shortcut_group):
|
||||||
emit(Constants.ByteCode.Pop,node)
|
emit(Constants.ByteCode.Pop,node)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#compile instructions for block
|
#compile instructions for block
|
||||||
#blocks are just groups of statements
|
#blocks are just groups of statements
|
||||||
func generate_block(node,statements:Array=[]):
|
func generate_block(node,statements:Array=[]):
|
||||||
|
@ -347,7 +332,7 @@ func generate_option(node,option):
|
||||||
# print('generating option')
|
# print('generating option')
|
||||||
var destination : String = option.destination
|
var destination : String = option.destination
|
||||||
|
|
||||||
if option.label == null || option.label.empty():
|
if option.label == null or option.label.empty():
|
||||||
#jump to another node
|
#jump to another node
|
||||||
emit(Constants.ByteCode.RunNode,node,[Program.Operand.new(destination)])
|
emit(Constants.ByteCode.RunNode,node,[Program.Operand.new(destination)])
|
||||||
else :
|
else :
|
||||||
|
@ -401,7 +386,7 @@ func generate_assignment(node,assignment):
|
||||||
#compile expression instructions
|
#compile expression instructions
|
||||||
func generate_expression(node,expression):
|
func generate_expression(node,expression):
|
||||||
# print('generating expression')
|
# print('generating expression')
|
||||||
#expression = value || func call
|
#expression = value or func call
|
||||||
match expression.type:
|
match expression.type:
|
||||||
Constants.ExpressionType.Value:
|
Constants.ExpressionType.Value:
|
||||||
generate_value(node,expression.value)
|
generate_value(node,expression.value)
|
||||||
|
@ -438,22 +423,6 @@ func generate_value(node,value):
|
||||||
_:
|
_:
|
||||||
printerr('Unrecognized valuenode type: %s' % value.value.type)
|
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 _last_error
|
|
||||||
|
|
||||||
func clear_errors()->void:
|
|
||||||
_errors = NO_ERROR
|
|
||||||
_last_error = NO_ERROR
|
|
||||||
|
|
||||||
func emit_error(error : int)->void:
|
|
||||||
_last_error = error
|
|
||||||
_errors |= _last_error
|
|
||||||
|
|
||||||
static func print_tokens(tokens:Array=[]):
|
static func print_tokens(tokens:Array=[]):
|
||||||
var list : PoolStringArray = []
|
var list : PoolStringArray = []
|
||||||
list.append('\n')
|
list.append('\n')
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
extends Object
|
extends Object
|
||||||
|
class_name Lexer
|
||||||
|
|
||||||
const Constants = preload('res://addons/Wol/core/constants.gd')
|
const Constants = preload('res://addons/Wol/core/constants.gd')
|
||||||
|
|
||||||
|
@ -23,16 +24,22 @@ var WHITESPACE : String = '\\s*'
|
||||||
|
|
||||||
var _states : Dictionary = {}
|
var _states : Dictionary = {}
|
||||||
var _defaultState : LexerState
|
var _defaultState : LexerState
|
||||||
|
|
||||||
var _currentState : LexerState
|
var _currentState : LexerState
|
||||||
|
|
||||||
var _indentStack : Array = []
|
var _indentStack : Array = []
|
||||||
var _shouldTrackIndent : bool = false
|
var _shouldTrackIndent : bool = false
|
||||||
|
|
||||||
|
var filename = ''
|
||||||
|
var title = ''
|
||||||
|
var text = ''
|
||||||
|
|
||||||
func _init():
|
func _init(_filename, _title, _text):
|
||||||
create_states()
|
create_states()
|
||||||
|
|
||||||
|
filename = _filename
|
||||||
|
title = _title
|
||||||
|
text = _text
|
||||||
|
|
||||||
func create_states():
|
func create_states():
|
||||||
var patterns : Dictionary = {}
|
var patterns : Dictionary = {}
|
||||||
patterns[Constants.TokenType.Text] = ['.*', 'any text']
|
patterns[Constants.TokenType.Text] = ['.*', 'any text']
|
||||||
|
@ -43,7 +50,7 @@ func create_states():
|
||||||
patterns[Constants.TokenType.LeftParen] = ['\\(', 'left parenthesis (']
|
patterns[Constants.TokenType.LeftParen] = ['\\(', 'left parenthesis (']
|
||||||
patterns[Constants.TokenType.RightParen] = ['\\)', 'right parenthesis )']
|
patterns[Constants.TokenType.RightParen] = ['\\)', 'right parenthesis )']
|
||||||
patterns[Constants.TokenType.EqualTo] = ['(==|is(?!\\w)|eq(?!\\w))', '"=", "is" or "eq"']
|
patterns[Constants.TokenType.EqualTo] = ['(==|is(?!\\w)|eq(?!\\w))', '"=", "is" or "eq"']
|
||||||
patterns[Constants.TokenType.EqualToOrAssign] = ['(=|to(?!\\w))', 'equal to "=" or assign "="']
|
patterns[Constants.TokenType.EqualToOrAssign] = ['(=|to(?!\\w))', '"=" or "to"']
|
||||||
patterns[Constants.TokenType.NotEqualTo] = ['(\\!=|neq(?!\\w))', '"!=" or "neq"']
|
patterns[Constants.TokenType.NotEqualTo] = ['(\\!=|neq(?!\\w))', '"!=" or "neq"']
|
||||||
patterns[Constants.TokenType.GreaterThanOrEqualTo] = ['(\\>=|gte(?!\\w))', '">=" or "gte"']
|
patterns[Constants.TokenType.GreaterThanOrEqualTo] = ['(\\>=|gte(?!\\w))', '">=" or "gte"']
|
||||||
patterns[Constants.TokenType.GreaterThan] = ['(\\>|gt(?!\\w))', '">" or "gt"']
|
patterns[Constants.TokenType.GreaterThan] = ['(\\>|gt(?!\\w))', '">" or "gt"']
|
||||||
|
@ -81,9 +88,9 @@ func create_states():
|
||||||
patterns[Constants.TokenType.ShortcutOption] = ['\\-\\>\\s*', '"->"']
|
patterns[Constants.TokenType.ShortcutOption] = ['\\-\\>\\s*', '"->"']
|
||||||
|
|
||||||
#compound states
|
#compound states
|
||||||
var shortcut_option : String= SHORTCUT + DASH + OPTION
|
var shortcut_option : String = SHORTCUT + DASH + OPTION
|
||||||
var shortcut_option_tag : String = shortcut_option + DASH + TAG
|
var shortcut_option_tag : String = shortcut_option + DASH + TAG
|
||||||
var command_or_expression : String= COMMAND + DASH + OR + DASH + EXPRESSION
|
var command_or_expression : String = COMMAND + DASH + OR + DASH + EXPRESSION
|
||||||
var link_destination : String = LINK + DASH + DESTINATION
|
var link_destination : String = LINK + DASH + DESTINATION
|
||||||
|
|
||||||
_states = {}
|
_states = {}
|
||||||
|
@ -91,7 +98,7 @@ func create_states():
|
||||||
_states[BASE] = LexerState.new(patterns)
|
_states[BASE] = LexerState.new(patterns)
|
||||||
_states[BASE].add_transition(Constants.TokenType.BeginCommand,COMMAND,true)
|
_states[BASE].add_transition(Constants.TokenType.BeginCommand,COMMAND,true)
|
||||||
_states[BASE].add_transition(Constants.TokenType.OptionStart,LINK,true)
|
_states[BASE].add_transition(Constants.TokenType.OptionStart,LINK,true)
|
||||||
_states[BASE].add_transition(Constants.TokenType.ShortcutOption,shortcut_option)
|
_states[BASE].add_transition(Constants.TokenType.ShortcutOption, shortcut_option)
|
||||||
_states[BASE].add_transition(Constants.TokenType.TagMarker,TAG,true)
|
_states[BASE].add_transition(Constants.TokenType.TagMarker,TAG,true)
|
||||||
_states[BASE].add_text_rule(Constants.TokenType.Text)
|
_states[BASE].add_text_rule(Constants.TokenType.Text)
|
||||||
|
|
||||||
|
@ -112,7 +119,7 @@ func create_states():
|
||||||
_states[COMMAND].add_transition(Constants.TokenType.ElseToken)
|
_states[COMMAND].add_transition(Constants.TokenType.ElseToken)
|
||||||
_states[COMMAND].add_transition(Constants.TokenType.ElseIf,EXPRESSION)
|
_states[COMMAND].add_transition(Constants.TokenType.ElseIf,EXPRESSION)
|
||||||
_states[COMMAND].add_transition(Constants.TokenType.EndIf)
|
_states[COMMAND].add_transition(Constants.TokenType.EndIf)
|
||||||
_states[COMMAND].add_transition(Constants.TokenType.Set,ASSIGNMENT)
|
_states[COMMAND].add_transition(Constants.TokenType.Set, ASSIGNMENT)
|
||||||
_states[COMMAND].add_transition(Constants.TokenType.EndCommand,BASE,true)
|
_states[COMMAND].add_transition(Constants.TokenType.EndCommand,BASE,true)
|
||||||
_states[COMMAND].add_transition(Constants.TokenType.Identifier,command_or_expression)
|
_states[COMMAND].add_transition(Constants.TokenType.Identifier,command_or_expression)
|
||||||
_states[COMMAND].add_text_rule(Constants.TokenType.Text)
|
_states[COMMAND].add_text_rule(Constants.TokenType.Text)
|
||||||
|
@ -173,9 +180,9 @@ func create_states():
|
||||||
for stateKey in _states.keys():
|
for stateKey in _states.keys():
|
||||||
_states[stateKey].stateName = stateKey
|
_states[stateKey].stateName = stateKey
|
||||||
|
|
||||||
func tokenize(text, title, filename):
|
func tokenize():
|
||||||
_indentStack.clear()
|
_indentStack.clear()
|
||||||
_indentStack.push_front(IntBoolPair.new(0,false))
|
_indentStack.push_front(IntBoolPair.new(0, false))
|
||||||
_shouldTrackIndent = false
|
_shouldTrackIndent = false
|
||||||
|
|
||||||
var tokens : Array = []
|
var tokens : Array = []
|
||||||
|
@ -188,7 +195,7 @@ func tokenize(text, title, filename):
|
||||||
var line_number : int = 1
|
var line_number : int = 1
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
tokens += tokenize_line(line, line_number, title, filename)
|
tokens += tokenize_line(line, line_number)
|
||||||
line_number += 1
|
line_number += 1
|
||||||
|
|
||||||
var endOfInput = Token.new(
|
var endOfInput = Token.new(
|
||||||
|
@ -201,14 +208,14 @@ func tokenize(text, title, filename):
|
||||||
|
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
func tokenize_line(line, line_number, title, filename):
|
func tokenize_line(line, line_number):
|
||||||
var tokenStack : Array = []
|
var tokenStack : Array = []
|
||||||
|
|
||||||
var freshLine = line.replace('\t',' ').replace('\r','')
|
var freshLine = line.replace('\t',' ').replace('\r','')
|
||||||
|
|
||||||
#record indentation
|
#record indentation
|
||||||
var indentation = line_indentation(line)
|
var indentation = line_indentation(line)
|
||||||
var prevIndentation : IntBoolPair = _indentStack.front()
|
var prevIndentation = _indentStack.front()
|
||||||
|
|
||||||
if _shouldTrackIndent && indentation > prevIndentation.key:
|
if _shouldTrackIndent && indentation > prevIndentation.key:
|
||||||
#we add an indenation token to record indent level
|
#we add an indenation token to record indent level
|
||||||
|
@ -259,7 +266,7 @@ func tokenize_line(line, line_number, title, filename):
|
||||||
|
|
||||||
var tokenText : String
|
var tokenText : String
|
||||||
|
|
||||||
if rule.tokenType == Constants.TokenType.Text:
|
if rule.token_type == Constants.TokenType.Text:
|
||||||
#if this is text then we back up to the most recent
|
#if this is text then we back up to the most recent
|
||||||
#delimiting token and treat everything from there as text.
|
#delimiting token and treat everything from there as text.
|
||||||
|
|
||||||
|
@ -289,29 +296,29 @@ func tokenize_line(line, line_number, title, filename):
|
||||||
column += tokenText.length()
|
column += tokenText.length()
|
||||||
|
|
||||||
#pre-proccess string
|
#pre-proccess string
|
||||||
if rule.tokenType == Constants.TokenType.Str:
|
if rule.token_type == Constants.TokenType.Str:
|
||||||
tokenText = tokenText.substr(1, tokenText.length() - 2)
|
tokenText = tokenText.substr(1, tokenText.length() - 2)
|
||||||
tokenText = tokenText.replace('\\\\', '\\')
|
tokenText = tokenText.replace('\\\\', '\\')
|
||||||
tokenText = tokenText.replace('\\\'','\'')
|
tokenText = tokenText.replace('\\\'','\'')
|
||||||
|
|
||||||
var token = Token.new(
|
var token = Token.new(
|
||||||
rule.tokenType,
|
rule.token_type,
|
||||||
_currentState,
|
_currentState,
|
||||||
filename,
|
filename,
|
||||||
line_number,
|
line_number,
|
||||||
column,
|
column,
|
||||||
tokenText
|
tokenText
|
||||||
)
|
)
|
||||||
token.delimitsText = rule.delimitsText
|
token.delimits_text = rule.delimits_text
|
||||||
|
|
||||||
tokenStack.push_front(token)
|
tokenStack.push_front(token)
|
||||||
|
|
||||||
if rule.enterState != null and rule.enterState.length() > 0:
|
if rule.enter_state != null and rule.enter_state.length() > 0:
|
||||||
if not _states.has(rule.enterState):
|
if not _states.has(rule.enter_state):
|
||||||
printerr('State[%s] not known - line(%s) col(%s)' % [rule.enterState, line_number, column])
|
printerr('State[%s] not known - line(%s) col(%s)' % [rule.enter_state, line_number, column])
|
||||||
return []
|
return []
|
||||||
|
|
||||||
enter_state(_states[rule.enterState])
|
enter_state(_states[rule.enter_state])
|
||||||
|
|
||||||
if _shouldTrackIndent:
|
if _shouldTrackIndent:
|
||||||
if _indentStack.front().key < indentation:
|
if _indentStack.front().key < indentation:
|
||||||
|
@ -323,7 +330,7 @@ func tokenize_line(line, line_number, title, filename):
|
||||||
if not matched:
|
if not matched:
|
||||||
var rules = []
|
var rules = []
|
||||||
for rule in _currentState.rules:
|
for rule in _currentState.rules:
|
||||||
rules.append('"%s" (%s)' % [Constants.token_type_name(rule.tokenType), rule.human_readable_identifier])
|
rules.append('"%s" (%s)' % [Constants.token_type_name(rule.token_type), rule.human_readable_identifier])
|
||||||
|
|
||||||
var error_data = [
|
var error_data = [
|
||||||
PoolStringArray(rules).join(', ') if rules.size() == 1 else PoolStringArray(rules.slice(0, rules.size() - 2)).join(', ') + ' or %s' % rules[-1],
|
PoolStringArray(rules).join(', ') if rules.size() == 1 else PoolStringArray(rules.slice(0, rules.size() - 2)).join(', ') + ' or %s' % rules[-1],
|
||||||
|
@ -368,17 +375,17 @@ class Token:
|
||||||
var column = -1
|
var column = -1
|
||||||
var text = ''
|
var text = ''
|
||||||
|
|
||||||
var delimitsText = false
|
var delimits_text = false
|
||||||
var paramCount = -1
|
var paramCount = -1
|
||||||
var lexerState = ''
|
var lexerState = ''
|
||||||
|
|
||||||
func _init(type, state, filename, line_number = -1, column = -1, value = ''):
|
func _init(_type, _state, _filename, _line_number = -1, _column = -1, _value = ''):
|
||||||
self.type = type
|
type = _type
|
||||||
self.lexerState = state.stateName
|
lexerState = _state.stateName
|
||||||
self.filename = filename
|
filename = _filename
|
||||||
self.line_number = line_number
|
line_number = _line_number
|
||||||
self.column = column
|
column = _column
|
||||||
self.value = value
|
value = _value
|
||||||
|
|
||||||
func _to_string():
|
func _to_string():
|
||||||
return '%s (%s) at %s:%s (state: %s)' % [Constants.token_type_name(type),value,line_number,column,lexerState]
|
return '%s (%s) at %s:%s (state: %s)' % [Constants.token_type_name(type),value,line_number,column,lexerState]
|
||||||
|
@ -390,8 +397,8 @@ class LexerState:
|
||||||
var rules : Array = []
|
var rules : Array = []
|
||||||
var track_indent : bool = false
|
var track_indent : bool = false
|
||||||
|
|
||||||
func _init(patterns):
|
func _init(_patterns):
|
||||||
self.patterns = patterns
|
patterns = _patterns
|
||||||
|
|
||||||
func add_transition(type : int, state : String = '',delimitText : bool = false)->Rule:
|
func add_transition(type : int, state : String = '',delimitText : bool = false)->Rule:
|
||||||
var pattern = '\\G%s' % patterns[type][0]
|
var pattern = '\\G%s' % patterns[type][0]
|
||||||
|
@ -407,48 +414,49 @@ class LexerState:
|
||||||
|
|
||||||
var delimiters:Array = []
|
var delimiters:Array = []
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
if rule.delimitsText:
|
if rule.delimits_text:
|
||||||
delimiters.append('%s' % rule.regex.get_pattern().substr(2))
|
delimiters.append('%s' % rule.regex.get_pattern().substr(2))
|
||||||
|
|
||||||
var pattern = '\\G((?!%s).)*' % [PoolStringArray(delimiters).join('|')]
|
var pattern = '\\G((?!%s).)*' % [PoolStringArray(delimiters).join('|')]
|
||||||
var rule : Rule = add_transition(type,state)
|
var rule : Rule = add_transition(type,state)
|
||||||
rule.regex = RegEx.new()
|
rule.regex = RegEx.new()
|
||||||
rule.regex.compile(pattern)
|
rule.regex.compile(pattern)
|
||||||
rule.isTextRule = true
|
rule.is_text_rule = true
|
||||||
return rule
|
return rule
|
||||||
|
|
||||||
func contains_text_rule()->bool:
|
func contains_text_rule()->bool:
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
if rule.isTextRule:
|
if rule.is_text_rule:
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
||||||
class Rule:
|
class Rule:
|
||||||
var regex : RegEx
|
var regex : RegEx
|
||||||
|
|
||||||
var enterState : String
|
var enter_state : String
|
||||||
var tokenType : int
|
var token_type : int
|
||||||
var isTextRule : bool
|
var is_text_rule : bool
|
||||||
var delimitsText : bool
|
var delimits_text : bool
|
||||||
var human_readable_identifier = ''
|
var human_readable_identifier = ''
|
||||||
|
|
||||||
func _init(type : int , regex : String, human_readable_identifier, enterState : String, delimitsText:bool):
|
func _init(_type, _regex, _human_readable_identifier, _enter_state, _delimits_text):
|
||||||
self.tokenType = type
|
token_type = _type
|
||||||
self.regex = RegEx.new()
|
|
||||||
self.regex.compile(regex)
|
regex = RegEx.new()
|
||||||
self.human_readable_identifier = human_readable_identifier
|
regex.compile(_regex)
|
||||||
self.enterState = enterState
|
|
||||||
self.delimitsText = delimitsText
|
human_readable_identifier = _human_readable_identifier
|
||||||
|
enter_state = _enter_state
|
||||||
|
delimits_text = _delimits_text
|
||||||
|
|
||||||
func _to_string():
|
func _to_string():
|
||||||
return '[Rule : %s (%s) - %s]' % [Constants.token_type_name(tokenType), human_readable_identifier, regex]
|
return '[Rule : %s (%s) - %s]' % [Constants.token_type_name(token_type), human_readable_identifier, regex]
|
||||||
|
|
||||||
class IntBoolPair:
|
class IntBoolPair:
|
||||||
var key : int
|
var key = -1
|
||||||
var value : bool
|
var value = false
|
||||||
|
|
||||||
func _init(key:int,value:bool):
|
func _init(_key, _value):
|
||||||
self.key = key
|
key = _key
|
||||||
self.value = value
|
value = _value
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,12 @@ extends Object
|
||||||
const Constants = preload('res://addons/Wol/core/constants.gd')
|
const Constants = preload('res://addons/Wol/core/constants.gd')
|
||||||
const Lexer = preload('res://addons/Wol/core/compiler/lexer.gd')
|
const Lexer = preload('res://addons/Wol/core/compiler/lexer.gd')
|
||||||
|
|
||||||
var _tokens = []
|
var tokens = []
|
||||||
var title = ''
|
var title = ''
|
||||||
|
|
||||||
func _init(tokens, title):
|
func _init(_title, _tokens):
|
||||||
self._tokens = tokens
|
title = _title
|
||||||
self.title = title
|
tokens = _tokens
|
||||||
|
|
||||||
enum Associativity {
|
enum Associativity {
|
||||||
Left,
|
Left,
|
||||||
|
@ -20,7 +20,7 @@ func parse_node():
|
||||||
return WolNode.new('Start', null, self)
|
return WolNode.new('Start', null, self)
|
||||||
|
|
||||||
func next_symbol_is(valid_types):
|
func next_symbol_is(valid_types):
|
||||||
var type = self._tokens.front().type
|
var type = self.tokens.front().type
|
||||||
for valid_type in valid_types:
|
for valid_type in valid_types:
|
||||||
if type == valid_type:
|
if type == valid_type:
|
||||||
return true
|
return true
|
||||||
|
@ -28,14 +28,14 @@ func next_symbol_is(valid_types):
|
||||||
|
|
||||||
# NOTE:0 look ahead for `<<` and `else`
|
# NOTE:0 look ahead for `<<` and `else`
|
||||||
func next_symbols_are(valid_types):
|
func next_symbols_are(valid_types):
|
||||||
var temporary = [] + _tokens
|
var temporary = [] + tokens
|
||||||
for type in valid_types:
|
for type in valid_types:
|
||||||
if temporary.pop_front().type != type:
|
if temporary.pop_front().type != type:
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
func expect_symbol(token_types = []):
|
func expect_symbol(token_types = []):
|
||||||
var token = _tokens.pop_front() as Lexer.Token
|
var token = tokens.pop_front() as Lexer.Token
|
||||||
|
|
||||||
if token_types.size() == 0:
|
if token_types.size() == 0:
|
||||||
if token.type == Constants.TokenType.EndOfInput:
|
if token.type == Constants.TokenType.EndOfInput:
|
||||||
|
@ -51,7 +51,6 @@ func expect_symbol(token_types = []):
|
||||||
for type in token_types:
|
for type in token_types:
|
||||||
token_names.append(Constants.token_type_name(type))
|
token_names.append(Constants.token_type_name(type))
|
||||||
|
|
||||||
|
|
||||||
var error_guess = '\n'
|
var error_guess = '\n'
|
||||||
|
|
||||||
if Constants.token_type_name(token.type) == 'Identifier' \
|
if Constants.token_type_name(token.type) == 'Identifier' \
|
||||||
|
@ -74,9 +73,6 @@ func expect_symbol(token_types = []):
|
||||||
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']
|
||||||
|
|
||||||
func tokens():
|
|
||||||
return _tokens
|
|
||||||
|
|
||||||
class ParseNode:
|
class ParseNode:
|
||||||
var name = ''
|
var name = ''
|
||||||
|
|
||||||
|
@ -84,21 +80,22 @@ class ParseNode:
|
||||||
var line_number = -1
|
var line_number = -1
|
||||||
var tags = []
|
var tags = []
|
||||||
|
|
||||||
func _init(parent, parser):
|
func _init(_parent, _parser):
|
||||||
self.parent = parent
|
parent = _parent
|
||||||
|
|
||||||
var tokens = parser.tokens() as Array
|
var tokens = _parser.tokens as Array
|
||||||
if tokens.size() > 0:
|
if tokens.size() > 0:
|
||||||
line_number = tokens.front().line_number
|
line_number = tokens.front().line_number
|
||||||
else:
|
else:
|
||||||
line_number = -1
|
line_number = -1
|
||||||
|
|
||||||
tags = []
|
tags = []
|
||||||
|
|
||||||
func tree_string(indent_level):
|
func tree_string(_indent_level):
|
||||||
return 'Not_implemented'
|
return 'Not_implemented'
|
||||||
|
|
||||||
func tags_to_string(indent_level):
|
func tags_to_string(_indent_level):
|
||||||
return '%s' % 'TAGS<tags_to_string>NOTIMPLEMENTED'
|
return 'TAGS<tags_to_string>NOTIMPLEMENTED'
|
||||||
|
|
||||||
func get_node_parent():
|
func get_node_parent():
|
||||||
var node = self
|
var node = self
|
||||||
|
@ -111,10 +108,6 @@ class ParseNode:
|
||||||
func tab(indent_level, input, newline = true):
|
func tab(indent_level, input, newline = true):
|
||||||
return '%*s| %s%s' % [ indent_level * 2, '', input, '' if !newline else '\n']
|
return '%*s| %s%s' % [ indent_level * 2, '', input, '' if !newline else '\n']
|
||||||
|
|
||||||
func set_parent(parent):
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
#this is a Wol Node - contains all the text
|
|
||||||
class WolNode extends ParseNode:
|
class WolNode extends ParseNode:
|
||||||
var source = ''
|
var source = ''
|
||||||
|
|
||||||
|
@ -123,7 +116,7 @@ class WolNode extends ParseNode:
|
||||||
|
|
||||||
func _init(name, parent, parser).(parent, parser):
|
func _init(name, parent, parser).(parent, parser):
|
||||||
self.name = name
|
self.name = name
|
||||||
while parser.tokens().size() > 0 \
|
while parser.tokens.size() > 0 \
|
||||||
and not parser.next_symbol_is([Constants.TokenType.Dedent, Constants.TokenType.EndOfInput]):
|
and not parser.next_symbol_is([Constants.TokenType.Dedent, Constants.TokenType.EndOfInput]):
|
||||||
statements.append(Statement.new(self, parser))
|
statements.append(Statement.new(self, parser))
|
||||||
|
|
||||||
|
@ -180,7 +173,7 @@ class Statement extends ParseNode:
|
||||||
type = Type.Line
|
type = Type.Line
|
||||||
|
|
||||||
else:
|
else:
|
||||||
printerr('Expected a statement but got %s instead. (probably an imbalanced if statement)' % parser.tokens().front()._to_string())
|
printerr('Expected a statement but got %s instead. (probably an imbalanced if statement)' % parser.tokens.front()._to_string())
|
||||||
|
|
||||||
var tags = []
|
var tags = []
|
||||||
|
|
||||||
|
@ -242,9 +235,8 @@ class CustomCommand extends ParseNode:
|
||||||
if (command_tokens.size() > 1 && command_tokens[0].type == Constants.TokenType.Identifier
|
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.LeftParen):
|
||||||
var p = get_script().new(command_tokens, parser.library)
|
var p = get_script().new(command_tokens, parser.library)
|
||||||
var expression = ExpressionNode.parse(self, p)
|
expression = ExpressionNode.parse(self, p)
|
||||||
type = Type.Expression
|
type = Type.Expression
|
||||||
self.expression = expression
|
|
||||||
else:
|
else:
|
||||||
#otherwise evaluuate command
|
#otherwise evaluuate command
|
||||||
type = Type.ClientCommand
|
type = Type.ClientCommand
|
||||||
|
@ -548,50 +540,43 @@ class ValueNode extends ParseNode:
|
||||||
func tree_string(indent_level):
|
func tree_string(indent_level):
|
||||||
return tab(indent_level, '%s' % value.value())
|
return tab(indent_level, '%s' % value.value())
|
||||||
|
|
||||||
|
|
||||||
#Expressions encompass a wide range of things like:
|
|
||||||
# math (1 + 2 - 5 * 3 / 10 % 2)
|
|
||||||
# Identifiers
|
|
||||||
# Values
|
|
||||||
class ExpressionNode extends ParseNode:
|
class ExpressionNode extends ParseNode:
|
||||||
var type
|
var type
|
||||||
var value
|
var value
|
||||||
var function
|
var function
|
||||||
var params = []#ExpressionNode
|
var parameters = []
|
||||||
|
|
||||||
func _init(parent, parser, value, function = '', params = []).(parent, parser):
|
func _init(parent, parser, _value, _function = '', _parameters = []).(parent, parser):
|
||||||
|
|
||||||
#no function - means value
|
if _value != null:
|
||||||
if value != null:
|
type = Constants.ExpressionType.Value
|
||||||
self.type = Constants.ExpressionType.Value
|
value = _value
|
||||||
self.value = value
|
else:
|
||||||
else:#function
|
type = Constants.ExpressionType.FunctionCall
|
||||||
|
function = _function
|
||||||
self.type = Constants.ExpressionType.FunctionCall
|
parameters = _parameters
|
||||||
self.function = function
|
|
||||||
self.params = params
|
|
||||||
|
|
||||||
func tree_string(indent_level):
|
func tree_string(indent_level):
|
||||||
var info = []
|
var info = []
|
||||||
match type:
|
match type:
|
||||||
Constants.ExpressionType.Value:
|
Constants.ExpressionType.Value:
|
||||||
return value.tree_string(indent_level)
|
return value.tree_string(indent_level)
|
||||||
|
|
||||||
Constants.ExpressionType.FunctionCall:
|
Constants.ExpressionType.FunctionCall:
|
||||||
info.append(tab(indent_level,'Func[%s - params(%s)]:{'%[function, params.size()]))
|
info.append(tab(indent_level,'Func[%s - parameters(%s)]:{'%[function, parameters.size()]))
|
||||||
for param in params:
|
for param in parameters:
|
||||||
info.append(param.tree_string(indent_level+1))
|
info.append(param.tree_string(indent_level+1))
|
||||||
info.append(tab(indent_level,'}'))
|
info.append(tab(indent_level,'}'))
|
||||||
|
|
||||||
return info.join('')
|
return info.join('')
|
||||||
|
|
||||||
#using Djikstra's shunting-yard algorithm to convert
|
# using Djikstra's shunting-yard algorithm to convert stream of expresions into postfix notation,
|
||||||
#stream of expresions into postfix notaion, then
|
# & then build a tree of expressions
|
||||||
#build a tree of expressions
|
|
||||||
static func parse(parent, parser):
|
static func parse(parent, parser):
|
||||||
var rpn = []
|
var rpn = []
|
||||||
var op_stack = []
|
var op_stack = []
|
||||||
|
|
||||||
#track params
|
#track parameters
|
||||||
var func_stack = []
|
var func_stack = []
|
||||||
|
|
||||||
var valid_types = [
|
var valid_types = [
|
||||||
|
@ -612,7 +597,7 @@ class ExpressionNode extends ParseNode:
|
||||||
var last
|
var last
|
||||||
|
|
||||||
#read expression content
|
#read expression content
|
||||||
while parser.tokens().size() > 0 && parser.next_symbol_is(valid_types):
|
while parser.tokens.size() > 0 && parser.next_symbol_is(valid_types):
|
||||||
var next = parser.expect_symbol(valid_types)
|
var next = parser.expect_symbol(valid_types)
|
||||||
|
|
||||||
if next.type == Constants.TokenType.Variable \
|
if next.type == Constants.TokenType.Variable \
|
||||||
|
@ -646,7 +631,7 @@ class ExpressionNode extends ParseNode:
|
||||||
# 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]):
|
||||||
printerr('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
|
||||||
|
@ -698,7 +683,7 @@ class ExpressionNode extends ParseNode:
|
||||||
op_stack.pop_back()
|
op_stack.pop_back()
|
||||||
if op_stack.back().type == Constants.TokenType.Identifier:
|
if op_stack.back().type == Constants.TokenType.Identifier:
|
||||||
#function call
|
#function call
|
||||||
#last token == left paren this == no params
|
#last token == left paren this == no parameters
|
||||||
#else
|
#else
|
||||||
#we have more than 1 param
|
#we have more than 1 param
|
||||||
if last.type != Constants.TokenType.LeftParen:
|
if last.type != Constants.TokenType.LeftParen:
|
||||||
|
@ -731,36 +716,35 @@ class ExpressionNode extends ParseNode:
|
||||||
if eval_stack.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])
|
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 function_parameters = []
|
||||||
for i in range(info.arguments):
|
for _i in range(info.arguments):
|
||||||
params.append(eval_stack.pop_back())
|
function_parameters.append(eval_stack.pop_back())
|
||||||
|
|
||||||
params.invert()
|
function_parameters.invert()
|
||||||
|
|
||||||
var function = get_func_name(next.type)
|
var function_name = get_func_name(next.type)
|
||||||
|
var expression = ExpressionNode.new(parent, parser, null, function_name, function_parameters)
|
||||||
var expression = ExpressionNode.new(parent, parser, null, function, params)
|
|
||||||
|
|
||||||
eval_stack.append(expression)
|
eval_stack.append(expression)
|
||||||
|
|
||||||
|
# A function call
|
||||||
elif next.type == Constants.TokenType.Identifier:
|
elif next.type == Constants.TokenType.Identifier:
|
||||||
#function call
|
var function_name = next.value
|
||||||
|
|
||||||
var function = next.value
|
var function_parameters = []
|
||||||
|
for _i in range(next.param_count):
|
||||||
var params = []#ExpressionNode
|
function_parameters.append(eval_stack.pop_back())
|
||||||
for i in range(next.param_count):
|
|
||||||
|
|
||||||
params.append(eval_stack.pop_back())
|
|
||||||
|
|
||||||
params.invert()
|
function_parameters.invert()
|
||||||
|
|
||||||
var expression = ExpressionNode.new(parent, parser, null, function, params)
|
var expression = ExpressionNode.new(parent, parser, null, function_name, function_parameters)
|
||||||
|
|
||||||
eval_stack.append(expression)
|
eval_stack.append(expression)
|
||||||
else: #raw value
|
|
||||||
var value = ValueNode.new(parent, parser, next)
|
# A raw value
|
||||||
var expression = ExpressionNode.new(parent, parser, value)
|
else:
|
||||||
|
var raw_value = ValueNode.new(parent, parser, next)
|
||||||
|
var expression = ExpressionNode.new(parent, parser, raw_value)
|
||||||
eval_stack.append(expression)
|
eval_stack.append(expression)
|
||||||
|
|
||||||
|
|
||||||
|
@ -769,45 +753,39 @@ class ExpressionNode extends ParseNode:
|
||||||
if eval_stack.size() != 1:
|
if eval_stack.size() != 1:
|
||||||
printerr('[%s] Error parsing expression (stack did not reduce correctly )' % first.name)
|
printerr('[%s] Error parsing expression (stack did not reduce correctly )' % first.name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return eval_stack.pop_back()
|
return eval_stack.pop_back()
|
||||||
|
|
||||||
static func get_func_name(type):
|
static func get_func_name(_type):
|
||||||
var string = ''
|
var string = ''
|
||||||
|
|
||||||
for key in Constants.TokenType.keys():
|
for key in Constants.TokenType.keys():
|
||||||
if Constants.TokenType[key] == type:
|
if Constants.TokenType[key] == _type:
|
||||||
return key
|
return key
|
||||||
return string
|
return string
|
||||||
|
|
||||||
static func is_apply_precedence(type, operator_stack):
|
static func is_apply_precedence(_type, operator_stack):
|
||||||
if operator_stack.size() == 0:
|
if operator_stack.size() == 0:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
if not Operator.is_op(type):
|
if not Operator.is_op(_type):
|
||||||
printerr('Unable to parse expression!')
|
assert(false, 'Unable to parse expression!')
|
||||||
|
|
||||||
var second = operator_stack.back().type
|
var second = operator_stack.back().type
|
||||||
|
|
||||||
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)
|
||||||
var second_info = Operator.op_info(second)
|
var second_info = Operator.op_info(second)
|
||||||
|
|
||||||
if (first_info.associativity == Associativity.Left &&
|
return \
|
||||||
first_info.precedence <= second_info.precedence):
|
(first_info.associativity == Associativity.Left \
|
||||||
return true
|
and first_info.precedence <= second_info.precedence) \
|
||||||
|
or \
|
||||||
if (first_info.associativity == Associativity.Right &&
|
(first_info.associativity == Associativity.Right \
|
||||||
first_info.precedence < second_info.precedence):
|
and first_info.precedence < second_info.precedence)
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
class Assignment extends ParseNode:
|
class Assignment extends ParseNode:
|
||||||
|
|
||||||
var destination
|
var destination
|
||||||
var value
|
var value
|
||||||
var operation
|
var operation
|
||||||
|
@ -845,15 +823,13 @@ class Assignment extends ParseNode:
|
||||||
]
|
]
|
||||||
|
|
||||||
class Operator extends ParseNode:
|
class Operator extends ParseNode:
|
||||||
|
|
||||||
var op_type
|
var op_type
|
||||||
|
|
||||||
func _init(parent, parser, op_type=null).(parent, parser):
|
func _init(parent, parser, _op_type = null).(parent, parser):
|
||||||
|
if _op_type == null :
|
||||||
if op_type == null :
|
op_type = parser.expect_symbol(Operator.op_types()).type
|
||||||
self.op_type = parser.expect_symbol(Operator.op_types()).type
|
|
||||||
else:
|
else:
|
||||||
self.op_type = op_type
|
op_type = _op_type
|
||||||
|
|
||||||
func tree_string(indent_level):
|
func tree_string(indent_level):
|
||||||
var info = []
|
var info = []
|
||||||
|
@ -923,18 +899,18 @@ class OperatorInfo:
|
||||||
var precedence = -1
|
var precedence = -1
|
||||||
var arguments = -1
|
var arguments = -1
|
||||||
|
|
||||||
func _init(associativity, precedence, arguments):
|
func _init(_associativity, _precedence, _arguments):
|
||||||
self.associativity = associativity
|
associativity = _associativity
|
||||||
self.precedence = precedence
|
precedence = _precedence
|
||||||
self.arguments = arguments
|
arguments = _arguments
|
||||||
|
|
||||||
class Clause:
|
class Clause:
|
||||||
var expression
|
var expression
|
||||||
var statements = [] #Statement
|
var statements = [] #Statement
|
||||||
|
|
||||||
func _init(expression = null, statements = []):
|
func _init(_expression = null, _statements = []):
|
||||||
self.expression = expression
|
expression = _expression
|
||||||
self.statements = statements
|
statements = _statements
|
||||||
|
|
||||||
func tree_string(indent_level):
|
func tree_string(indent_level):
|
||||||
var info = []
|
var info = []
|
||||||
|
|
|
@ -49,6 +49,7 @@ func set_node(name = DEFAULT_START):
|
||||||
_vm.set_node(name)
|
_vm.set_node(name)
|
||||||
|
|
||||||
func start():
|
func start():
|
||||||
|
print('got here')
|
||||||
if _vm.executionState == Constants.ExecutionState.Stopped:
|
if _vm.executionState == Constants.ExecutionState.Stopped:
|
||||||
_vm.resume()
|
_vm.resume()
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,35 @@
|
||||||
extends Object
|
extends Object
|
||||||
var Value : GDScript = load("res://addons/Wol/core/value.gd")
|
var Value : GDScript = load("res://addons/Wol/core/value.gd")
|
||||||
|
|
||||||
#name of the function
|
var name = ''
|
||||||
var name : String
|
# NOTE: -1 means variable arguments
|
||||||
|
var parameter_count = 0
|
||||||
|
var function
|
||||||
|
var returns_value = false
|
||||||
|
|
||||||
#param count of this function
|
func _init(_name, _parameter_count, _function = null, _returns_value = false):
|
||||||
# -1 means variable arguments
|
name = _name
|
||||||
var paramCount : int = 0
|
parameter_count = _parameter_count
|
||||||
#function implementation
|
function = _function
|
||||||
var function : FuncRef
|
returns_value = _returns_value
|
||||||
var returnsValue : bool = false
|
|
||||||
|
|
||||||
func _init(name: String, paramCount: int, function: FuncRef = null, returnsValue: bool = false):
|
func invoke(parameters = []):
|
||||||
self.name = name
|
|
||||||
self.paramCount = paramCount
|
|
||||||
self.function = function
|
|
||||||
self.returnsValue = returnsValue
|
|
||||||
|
|
||||||
func invoke(params = []):
|
|
||||||
var length = 0
|
var length = 0
|
||||||
if params != null:
|
if parameters != null:
|
||||||
length = params.size()
|
length = parameters.size()
|
||||||
|
|
||||||
if check_param_count(length):
|
if check_param_count(length):
|
||||||
if returnsValue:
|
if returns_value:
|
||||||
if length > 0:
|
if length > 0:
|
||||||
return Value.new(function.call_funcv(params))
|
return Value.new(function.call_funcv(parameters))
|
||||||
else:
|
else:
|
||||||
return Value.new(function.call_func())
|
return Value.new(function.call_func())
|
||||||
else:
|
else:
|
||||||
if length > 0:
|
if length > 0:
|
||||||
function.call_funcv(params)
|
function.call_funcv(parameters)
|
||||||
else :
|
else :
|
||||||
function.call_func()
|
function.call_func()
|
||||||
return null
|
return null
|
||||||
|
|
||||||
func check_param_count(paramCount: int):
|
func check_param_count(_parameter_count):
|
||||||
return self.paramCount == paramCount || self.paramCount == -1
|
return parameter_count == _parameter_count or parameter_count == -1
|
||||||
|
|
|
@ -15,28 +15,28 @@ class Line:
|
||||||
var implicit = false
|
var implicit = false
|
||||||
var meta = []
|
var meta = []
|
||||||
|
|
||||||
func _init(text, node_name, line_number, file_name, implicit, meta):
|
func _init(_text, _node_name, _line_number, _file_name, _implicit, _meta):
|
||||||
self.text = text
|
text = _text
|
||||||
self.node_name = node_name
|
node_name = _node_name
|
||||||
self.file_name = file_name
|
file_name = _file_name
|
||||||
self.implicit = implicit
|
implicit = _implicit
|
||||||
self.meta = meta
|
meta = _meta
|
||||||
|
|
||||||
class Option:
|
class Option:
|
||||||
var line
|
var line
|
||||||
var id = -1
|
var id = -1
|
||||||
var destination = ''
|
var destination = ''
|
||||||
|
|
||||||
func _init(line, id, destination):
|
func _init(_line, _id, _destination):
|
||||||
self.line = line
|
line = _line
|
||||||
self.id = id
|
id = _id
|
||||||
self.destination = destination
|
destination = _destination
|
||||||
|
|
||||||
class Command:
|
class Command:
|
||||||
var command = ''
|
var command = ''
|
||||||
|
|
||||||
func _init(command):
|
func _init(_command):
|
||||||
self.command = command
|
command = _command
|
||||||
|
|
||||||
class WolNode:
|
class WolNode:
|
||||||
var name = ''
|
var name = ''
|
||||||
|
@ -55,15 +55,15 @@ class WolNode:
|
||||||
source_id = other.source_id
|
source_id = other.source_id
|
||||||
|
|
||||||
func equals(other):
|
func equals(other):
|
||||||
if other.get_script() != self.get_script():
|
if other.get_script() != get_script():
|
||||||
return false
|
return false
|
||||||
if other.name != self.name:
|
if other.name != name:
|
||||||
return false
|
return false
|
||||||
if other.instructions != self.instructions:
|
if other.instructions != instructions:
|
||||||
return false
|
return false
|
||||||
if other.label != self.label:
|
if other.labels != labels:
|
||||||
return false
|
return false
|
||||||
if other.sourceId != self.sourceId:
|
if other.source_id != source_id:
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
@ -82,33 +82,33 @@ class Operand:
|
||||||
var value
|
var value
|
||||||
var type
|
var type
|
||||||
|
|
||||||
func _init(value):
|
func _init(_value):
|
||||||
if typeof(value) == TYPE_OBJECT and value.get_script() == self.get_script():
|
if typeof(_value) == TYPE_OBJECT and _value.get_script() == get_script():
|
||||||
set_value(value.value)
|
set_value(_value.value)
|
||||||
else:
|
else:
|
||||||
set_value(value)
|
set_value(_value)
|
||||||
|
|
||||||
func set_value(value):
|
func set_value(_value):
|
||||||
match typeof(value):
|
match typeof(_value):
|
||||||
TYPE_REAL,TYPE_INT:
|
TYPE_REAL,TYPE_INT:
|
||||||
set_number(value)
|
set_number(_value)
|
||||||
TYPE_BOOL:
|
TYPE_BOOL:
|
||||||
set_boolean(value)
|
set_boolean(_value)
|
||||||
TYPE_STRING:
|
TYPE_STRING:
|
||||||
set_string(value)
|
set_string(_value)
|
||||||
|
|
||||||
func set_boolean(value):
|
func set_boolean(_value):
|
||||||
_value(value)
|
value = _value
|
||||||
type = ValueType.BooleanValue
|
type = ValueType.BooleanValue
|
||||||
return self
|
return self
|
||||||
|
|
||||||
func set_string(value):
|
func set_string(_value):
|
||||||
_value(value)
|
value = _value
|
||||||
type = ValueType.StringValue
|
type = ValueType.StringValue
|
||||||
return self
|
return self
|
||||||
|
|
||||||
func set_number(value):
|
func set_number(_value):
|
||||||
_value(value)
|
value = _value
|
||||||
type = ValueType.FloatValue
|
type = ValueType.FloatValue
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -122,9 +122,6 @@ class Operand:
|
||||||
func _to_string():
|
func _to_string():
|
||||||
return "Operand[%s:%s]" % [type, value]
|
return "Operand[%s:%s]" % [type, value]
|
||||||
|
|
||||||
func _value(value):
|
|
||||||
self.value = value
|
|
||||||
|
|
||||||
class Instruction:
|
class Instruction:
|
||||||
var operation = -1
|
var operation = -1
|
||||||
var operands = []
|
var operands = []
|
||||||
|
@ -134,9 +131,6 @@ class Instruction:
|
||||||
self.operation = other.operation
|
self.operation = other.operation
|
||||||
self.operands += other.operands
|
self.operands += other.operands
|
||||||
|
|
||||||
func dump(program, library):
|
|
||||||
return "InstructionInformation:NotImplemented"
|
|
||||||
|
|
||||||
func _to_string():
|
func _to_string():
|
||||||
return Constants.bytecode_name(operation) + ':' + operands as String
|
return Constants.bytecode_name(operation) + ':' + operands as String
|
||||||
|
|
||||||
|
|
|
@ -219,27 +219,27 @@ func run_instruction(instruction)->bool:
|
||||||
|
|
||||||
var function = _dialogue.library.get_function(functionName)
|
var function = _dialogue.library.get_function(functionName)
|
||||||
|
|
||||||
var expectedParamCount : int = function.paramCount
|
var expected_parameter_count : int = function.paramCount
|
||||||
var actualParamCount : int = _state.pop_value().as_number()
|
var actual_parameter_count : int = _state.pop_value().as_number()
|
||||||
|
|
||||||
#if function takes in -1 params disregard
|
#if function takes in -1 params disregard
|
||||||
#expect the compiler to have placed the number of params
|
#expect the compiler to have placed the number of params
|
||||||
#at the top of the stack
|
#at the top of the stack
|
||||||
if expectedParamCount == -1:
|
if expected_parameter_count == -1:
|
||||||
expectedParamCount = actualParamCount
|
expected_parameter_count = actual_parameter_count
|
||||||
|
|
||||||
if expectedParamCount != actualParamCount:
|
if expected_parameter_count != actual_parameter_count:
|
||||||
printerr('Function %s expected %d parameters but got %d instead' %[functionName,
|
printerr('Function %s expected %d parameters but got %d instead' %[functionName,
|
||||||
expectedParamCount,actualParamCount])
|
expected_parameter_count,actual_parameter_count])
|
||||||
return false
|
return false
|
||||||
|
|
||||||
var result
|
var result
|
||||||
|
|
||||||
if actualParamCount == 0:
|
if actual_parameter_count == 0:
|
||||||
result = function.invoke()
|
result = function.invoke()
|
||||||
else:
|
else:
|
||||||
var params : Array = []#value
|
var params : Array = []#value
|
||||||
for i in range(actualParamCount):
|
for _i in range(actual_parameter_count):
|
||||||
params.push_front(_state.pop_value())
|
params.push_front(_state.pop_value())
|
||||||
|
|
||||||
result = function.invoke(params)
|
result = function.invoke(params)
|
||||||
|
@ -352,6 +352,6 @@ class SimpleEntry:
|
||||||
var key
|
var key
|
||||||
var value
|
var value
|
||||||
|
|
||||||
func _init(key, value):
|
func _init(_key, _value):
|
||||||
self.key = key
|
key = _key
|
||||||
self.value = value
|
value = _value
|
||||||
|
|
|
@ -20,6 +20,11 @@ _global_script_classes=[ {
|
||||||
"path": "res://addons/Wol/core/constants.gd"
|
"path": "res://addons/Wol/core/constants.gd"
|
||||||
}, {
|
}, {
|
||||||
"base": "Object",
|
"base": "Object",
|
||||||
|
"class": "Lexer",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://addons/Wol/core/compiler/lexer.gd"
|
||||||
|
}, {
|
||||||
|
"base": "Object",
|
||||||
"class": "Program",
|
"class": "Program",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://addons/Wol/core/program.gd"
|
"path": "res://addons/Wol/core/program.gd"
|
||||||
|
@ -32,6 +37,7 @@ _global_script_classes=[ {
|
||||||
_global_script_class_icons={
|
_global_script_class_icons={
|
||||||
"Compiler": "",
|
"Compiler": "",
|
||||||
"Constants": "",
|
"Constants": "",
|
||||||
|
"Lexer": "",
|
||||||
"Program": "",
|
"Program": "",
|
||||||
"Wol": ""
|
"Wol": ""
|
||||||
}
|
}
|
||||||
|
@ -42,6 +48,12 @@ config/name="Wol"
|
||||||
run/main_scene="res://Dialogue.tscn"
|
run/main_scene="res://Dialogue.tscn"
|
||||||
config/icon="res://icon.png"
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
|
||||||
|
gdscript/warnings/treat_warnings_as_errors=true
|
||||||
|
gdscript/warnings/exclude_addons=false
|
||||||
|
gdscript/warnings/return_value_discarded=false
|
||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
enabled=PoolStringArray( "res://addons/Wol/plugin.cfg" )
|
enabled=PoolStringArray( "res://addons/Wol/plugin.cfg" )
|
||||||
|
|
Reference in a new issue