diff --git a/addons/Wol/Wol.gd b/addons/Wol/Wol.gd index 78895f1..da08ac3 100644 --- a/addons/Wol/Wol.gd +++ b/addons/Wol/Wol.gd @@ -1,5 +1,6 @@ tool extends Node +class_name Wol signal node_started(node) signal line(line) @@ -69,7 +70,7 @@ func set_path(_path): func _handle_line(line): var id = line.id - var string = program.wolStrings[id] + var string = program.strings[id] call_deferred('emit_signal', 'line', string) return WolGlobals.HandlerState.PauseExecution diff --git a/addons/Wol/autoloads/execution_states.gd b/addons/Wol/autoloads/execution_states.gd index 818bf4c..1501aa6 100644 --- a/addons/Wol/autoloads/execution_states.gd +++ b/addons/Wol/autoloads/execution_states.gd @@ -210,21 +210,3 @@ func bytecode_name(bytecode): 'Stop', 'RunNode' ][bytecode] - -#combine all the programs in the provided array -static func combine_programs(programs = []): - var WolProgram = load('res://addons/Wol/core/program/program.gd') - if programs.size() == 0: - printerr('no programs to combine - you failure') - return - var p = WolProgram.new() - - for program in programs: - for nodeKey in program.wolNodes.keys(): - if p.wolNodes.has(nodeKey): - printerr('Program with duplicate node names %s '% nodeKey) - return - p.wolNodes[nodeKey] = program.wolNodes[nodeKey] - - return p - diff --git a/addons/Wol/core/compiler/compiler.gd b/addons/Wol/core/compiler/compiler.gd index 14333b1..745f1a6 100644 --- a/addons/Wol/core/compiler/compiler.gd +++ b/addons/Wol/core/compiler/compiler.gd @@ -1,12 +1,8 @@ extends Object +class_name Compiler const Lexer = preload("res://addons/Wol/core/compiler/lexer.gd") -const LineInfo = preload("res://addons/Wol/core/program/line.gd") -const WolNode = preload("res://addons/Wol/core/program/node.gd") -const Instruction = preload("res://addons/Wol/core/program/instruction.gd") -const WolProgram = preload("res://addons/Wol/core/program/program.gd") -const Operand = preload("res://addons/Wol/core/program/operand.gd") - +const Program = preload("res://addons/Wol/core/program.gd") #patterns const INVALIDTITLENAME = "[\\[<>\\]{}\\|:\\s#\\$]" @@ -23,19 +19,19 @@ var _errors : int var _lastError : int #-----Class vars -var _currentNode : WolNode +var _currentNode : Program.WolNode var _rawText : bool var _fileName : String var _containsImplicitStringTags : bool var _labelCount : int = 0 -# +# var _stringTable : Dictionary = {} var _stringCount : int = 0 # var _tokens : Dictionary = {} -static func compile_string(source: String, filename: String) -> WolProgram: +static func compile_string(source: String, filename: String): var Parser = load("res://addons/Wol/core/compiler/parser.gd") var Compiler = load("res://addons/Wol/core/compiler/compiler.gd") @@ -107,25 +103,25 @@ static func compile_string(source: String, filename: String) -> WolProgram: #--- End parsing nodes--- - var program = WolProgram.new() + var program = Program.new() #compile nodes for node in parsedNodes: compiler.compile_node(program, node) for key in compiler._stringTable: - program.wolStrings[key] = compiler._stringTable[key] + program.strings[key] = compiler._stringTable[key] return program -func compile_node(program:WolProgram,parsedNode)->void: - if program.wolNodes.has(parsedNode.name): +func compile_node(program, parsedNode): + if program.nodes.has(parsedNode.name): emit_error(DUPLICATE_NODES_IN_PROGRAM) printerr("Duplicate node in program: %s" % parsedNode.name) else: - var nodeCompiled : WolNode = WolNode.new() + var nodeCompiled = Program.WolNode.new() - nodeCompiled.nodeName = parsedNode.name + nodeCompiled.name = parsedNode.name nodeCompiled.tags = parsedNode.tags #raw text @@ -135,7 +131,7 @@ func compile_node(program:WolProgram,parsedNode)->void: else: #compile node var startLabel : String = register_label() - emit(WolGlobals.ByteCode.Label,nodeCompiled,[Operand.new(startLabel)]) + emit(WolGlobals.ByteCode.Label,nodeCompiled,[Program.Operand.new(startLabel)]) for statement in parsedNode.statements: generate_statement(nodeCompiled,statement) @@ -158,7 +154,7 @@ func compile_node(program:WolProgram,parsedNode)->void: emit(WolGlobals.ByteCode.Stop, nodeCompiled) - program.wolNodes[nodeCompiled.nodeName] = nodeCompiled + program.nodes[nodeCompiled.name] = nodeCompiled func register_string(text:String,nodeName:String,id:String="",lineNumber:int=-1,tags:Array=[])->String: var lineIdUsed : String @@ -179,7 +175,7 @@ func register_string(text:String,nodeName:String,id:String="",lineNumber:int=-1, lineIdUsed = id implicit = false - var stringInfo : LineInfo = LineInfo.new(text,nodeName,lineNumber,_fileName,implicit,tags) + var stringInfo = Program.Line.new(text,nodeName,lineNumber,_fileName,implicit,tags) #add to string table and return id self._stringTable[lineIdUsed] = stringInfo @@ -189,17 +185,18 @@ func register_label(comment:String="")->String: _labelCount+=1 return "L%s%s" %[ _labelCount , comment] -func emit(bytecode,node:WolNode=_currentNode,operands:Array=[]): - var instruction : Instruction = Instruction.new(null) +func emit(bytecode, node = _currentNode, operands = []): + var instruction = Program.Instruction.new(null) instruction.operation = bytecode instruction.operands = operands - # print("emitting instruction to %s"%node.nodeName) - if(node == null): + if node == null: printerr("trying to emit to null node with byteCode: %s" % bytecode) - return; + return + node.instructions.append(instruction) - if bytecode == WolGlobals.ByteCode.Label : + + if bytecode == WolGlobals.ByteCode.Label: #add to label table node.labels[instruction.operands[0].value] = node.instructions.size()-1 @@ -246,13 +243,13 @@ func generate_custom_command(node,command): if commandString == "stop": emit(WolGlobals.ByteCode.Stop,node) else : - emit(WolGlobals.ByteCode.RunCommand,node,[Operand.new(commandString)]) + emit(WolGlobals.ByteCode.RunCommand,node,[Program.Operand.new(commandString)]) #compile instructions for linetags and use them # \#line:number func generate_line(node,statement,line:String): - var num : String = register_string(line,node.nodeName,"",statement.lineNumber,[]); - emit(WolGlobals.ByteCode.RunLine,node,[Operand.new(num)]) + var num : String = register_string(line, node.name, "", statement.lineNumber, []); + emit(WolGlobals.ByteCode.RunLine, node, [Program.Operand.new(num)]) func generate_shortcut_group(node,shortcutGroup): # print("generating shortcutoptopn group") @@ -271,16 +268,16 @@ func generate_shortcut_group(node,shortcutGroup): if option.condition != null : endofClause = register_label("conditional_%s"%optionCount) generate_expression(node,option.condition) - emit(WolGlobals.ByteCode.JumpIfFalse,node,[Operand.new(endofClause)]) + emit(WolGlobals.ByteCode.JumpIfFalse,node,[Program.Operand.new(endofClause)]) var labelLineId : String = ""#no tag TODO: ADD TAG SUPPORT var labelStringId : String = register_string(option.label,node.nodeName, labelLineId,option.lineNumber,[]) - emit(WolGlobals.ByteCode.AddOption,node,[Operand.new(labelStringId),Operand.new(opDestination)]) + emit(WolGlobals.ByteCode.AddOption,node,[Program.Operand.new(labelStringId),Program.Operand.new(opDestination)]) if option.condition != null : - emit(WolGlobals.ByteCode.Label,node,[Operand.new(endofClause)]) + emit(WolGlobals.ByteCode.Label,node,[Program.Operand.new(endofClause)]) emit(WolGlobals.ByteCode.Pop,node) optionCount+=1 @@ -291,15 +288,15 @@ func generate_shortcut_group(node,shortcutGroup): optionCount = 0 for option in shortcutGroup.options: - emit(WolGlobals.ByteCode.Label,node,[Operand.new(labels[optionCount])]) + emit(WolGlobals.ByteCode.Label,node,[Program.Operand.new(labels[optionCount])]) if option.node != null : generate_block(node,option.node.statements) - emit(WolGlobals.ByteCode.JumpTo,node,[Operand.new(end)]) + emit(WolGlobals.ByteCode.JumpTo,node,[Program.Operand.new(end)]) optionCount+=1 #end of option group - emit(WolGlobals.ByteCode.Label,node,[Operand.new(end)]) + emit(WolGlobals.ByteCode.Label,node,[Program.Operand.new(end)]) #clean up emit(WolGlobals.ByteCode.Pop,node) @@ -325,19 +322,19 @@ func generate_if(node,ifStatement): if clause.expression!=null: generate_expression(node,clause.expression) - emit(WolGlobals.ByteCode.JumpIfFalse,node,[Operand.new(endClause)]) + emit(WolGlobals.ByteCode.JumpIfFalse,node,[Program.Operand.new(endClause)]) generate_block(node,clause.statements) - emit(WolGlobals.ByteCode.JumpTo,node,[Operand.new(endif)]) + emit(WolGlobals.ByteCode.JumpTo,node,[Program.Operand.new(endif)]) if clause.expression!=null: - emit(WolGlobals.ByteCode.Label,node,[Operand.new(endClause)]) + emit(WolGlobals.ByteCode.Label,node,[Program.Operand.new(endClause)]) if clause.expression!=null: emit(WolGlobals.ByteCode.Pop) - emit(WolGlobals.ByteCode.Label,node,[Operand.new(endif)]) + emit(WolGlobals.ByteCode.Label,node,[Program.Operand.new(endif)]) #compile instructions for options @@ -347,12 +344,12 @@ func generate_option(node,option): if option.label == null || option.label.empty(): #jump to another node - emit(WolGlobals.ByteCode.RunNode,node,[Operand.new(destination)]) + emit(WolGlobals.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,[]) - emit(WolGlobals.ByteCode.AddOption,node,[Operand.new(stringID),Operand.new(destination)]) + emit(WolGlobals.ByteCode.AddOption,node,[Program.Operand.new(stringID),Program.Operand.new(destination)]) #compile instructions for assigning values @@ -375,22 +372,22 @@ func generate_assignment(node,assignment): match assignment.operation: WolGlobals.TokenType.AddAssign: emit(WolGlobals.ByteCode.CallFunc,node, - [Operand.new(WolGlobals.token_type_name(WolGlobals.TokenType.Add))]) + [Program.Operand.new(WolGlobals.token_type_name(WolGlobals.TokenType.Add))]) WolGlobals.TokenType.MinusAssign: emit(WolGlobals.ByteCode.CallFunc,node, - [Operand.new(WolGlobals.token_type_name(WolGlobals.TokenType.Minus))]) + [Program.Operand.new(WolGlobals.token_type_name(WolGlobals.TokenType.Minus))]) WolGlobals.TokenType.MultiplyAssign: emit(WolGlobals.ByteCode.CallFunc,node, - [Operand.new(WolGlobals.token_type_name(WolGlobals.TokenType.MultiplyAssign))]) + [Program.Operand.new(WolGlobals.token_type_name(WolGlobals.TokenType.MultiplyAssign))]) WolGlobals.TokenType.DivideAssign: emit(WolGlobals.ByteCode.CallFunc,node, - [Operand.new(WolGlobals.token_type_name(WolGlobals.TokenType.DivideAssign))]) + [Program.Operand.new(WolGlobals.token_type_name(WolGlobals.TokenType.DivideAssign))]) _: printerr("Unable to generate assignment") #stack contains destination value #store the top of the stack in variable - emit(WolGlobals.ByteCode.StoreVariable,node,[Operand.new(assignment.destination)]) + emit(WolGlobals.ByteCode.StoreVariable,node,[Program.Operand.new(assignment.destination)]) #clean stack emit(WolGlobals.ByteCode.Pop,node) @@ -409,10 +406,10 @@ func generate_expression(node,expression): generate_expression(node,param) #put the num of of params to stack - emit(WolGlobals.ByteCode.PushNumber,node,[Operand.new(expression.params.size())]) + emit(WolGlobals.ByteCode.PushNumber,node,[Program.Operand.new(expression.params.size())]) #call function - emit(WolGlobals.ByteCode.CallFunc,node,[Operand.new(expression.function)]) + emit(WolGlobals.ByteCode.CallFunc,node,[Program.Operand.new(expression.function)]) _: printerr("no expression") @@ -422,15 +419,15 @@ func generate_value(node,value): #push value to stack match value.value.type: WolGlobals.ValueType.Number: - emit(WolGlobals.ByteCode.PushNumber,node,[Operand.new(value.value.as_number())]) + emit(WolGlobals.ByteCode.PushNumber,node,[Program.Operand.new(value.value.as_number())]) WolGlobals.ValueType.Str: var id : String = register_string(value.value.as_string(), node.nodeName,"",value.lineNumber,[]) - emit(WolGlobals.ByteCode.PushString,node,[Operand.new(id)]) + emit(WolGlobals.ByteCode.PushString,node,[Program.Operand.new(id)]) WolGlobals.ValueType.Boolean: - emit(WolGlobals.ByteCode.PushBool,node,[Operand.new(value.value.as_bool())]) + emit(WolGlobals.ByteCode.PushBool,node,[Program.Operand.new(value.value.as_bool())]) WolGlobals.ValueType.Variable: - emit(WolGlobals.ByteCode.PushVariable,node,[Operand.new(value.value.variable)]) + emit(WolGlobals.ByteCode.PushVariable,node,[Program.Operand.new(value.value.variable)]) WolGlobals.ValueType.Nullean: emit(WolGlobals.ByteCode.PushNull,node) _: diff --git a/addons/Wol/core/dialogue.gd b/addons/Wol/core/dialogue.gd index 8a3af92..3d3ee4e 100644 --- a/addons/Wol/core/dialogue.gd +++ b/addons/Wol/core/dialogue.gd @@ -7,7 +7,6 @@ const StandardLibrary = preload("res://addons/Wol/core/libraries/standard.gd") const VirtualMachine = preload("res://addons/Wol/core/virtual_machine.gd") const WolLibrary = preload("res://addons/Wol/core/library.gd") const Value = preload("res://addons/Wol/core/value.gd") -const WolProgram = preload("res://addons/Wol/core/program/program.gd") var _variableStorage @@ -74,7 +73,7 @@ func stop(): _vm.stop() func get_all_nodes(): - return _program.wolNodes.keys() + return _program.nodes.keys() func current_node(): return _vm.get_current() diff --git a/addons/Wol/core/program.gd b/addons/Wol/core/program.gd new file mode 100644 index 0000000..e3ad920 --- /dev/null +++ b/addons/Wol/core/program.gd @@ -0,0 +1,124 @@ +extends Object +class_name WolProgram + +var name = '' +var strings = {} +var nodes = {} + +class Line: + var text = '' + var node_name = '' + var line_number = -1 + var file_name = '' + var implicit = false + var meta = [] + + func _init(text, node_name, line_number, file_name, implicit, meta): + self.text = text + self.node_name = node_name + self.file_name = file_name + self.implicit = implicit + self.meta = meta + +class WolNode: + var name = '' + var instructions = [] + var labels = {} + var tags = [] + var source_id = '' + + func _init(other = null): + if other != null and other.get_script() == self.get_script(): + name = other.name + instructions += other.instructions + for key in other.labels.keys(): + labels[key] = other.labels[key] + tags += other.tags + source_id = other.source_id + + func equals(other): + if other.get_script() != self.get_script(): + return false + if other.name != self.name: + return false + if other.instructions != self.instructions: + return false + if other.label != self.label: + return false + if other.sourceId != self.sourceId: + return false + return true + + func _to_string(): + return "WolNode[%s:%s]" % [name, source_id] + +# TODO: Make this make sense +class Operand: + enum ValueType { + None, + StringValue, + BooleanValue, + FloatValue + } + + var value + var type + + func _init(value): + if typeof(value) == TYPE_OBJECT and value.get_script() == self.get_script(): + set_value(value.value) + else: + set_value(value) + + func set_value(value): + match typeof(value): + TYPE_REAL,TYPE_INT: + set_number(value) + TYPE_BOOL: + set_boolean(value) + TYPE_STRING: + set_string(value) + + func set_boolean(value): + _value(value) + type = ValueType.BooleanValue + return self + + func set_string(value): + _value(value) + type = ValueType.StringValue + return self + + func set_number(value): + _value(value) + type = ValueType.FloatValue + return self + + func clear_value(): + type = ValueType.None + value = null + + func clone(): + return get_script().new(self) + + func _to_string(): + return "Operand[%s:%s]" % [type, value] + + func _value(value): + self.value = value + +class Instruction: + var operation = -1 + var operands = [] + + func _init(other = null): + if other != null and other.get_script() == self.get_script(): + self.operation = other.operation + self.operands += other.operands + + func dump(program, library): + return "InstructionInformation:NotImplemented" + + func _to_string(): + return WolGlobals.bytecode_name(operation) + ':' + operands as String + diff --git a/addons/Wol/core/program/instruction.gd b/addons/Wol/core/program/instruction.gd deleted file mode 100644 index 5bdbe3c..0000000 --- a/addons/Wol/core/program/instruction.gd +++ /dev/null @@ -1,17 +0,0 @@ -extends Object - -const Operand = preload("res://addons/Wol/core/program/operand.gd") - -var operation : int #bytcode -var operands : Array #Operands - -func _init(other=null): - if other != null && other.get_script() == self.get_script(): - self.operation = other.operation - self.operands += other.operands - -func dump(program,library)->String: - return "InstructionInformation:NotImplemented" - -func _to_string(): - return WolGlobals.bytecode_name(operation) + ':' + operands as String diff --git a/addons/Wol/core/program/line.gd b/addons/Wol/core/program/line.gd deleted file mode 100644 index 7c5d86a..0000000 --- a/addons/Wol/core/program/line.gd +++ /dev/null @@ -1,16 +0,0 @@ -extends Object -class_name WolLine - -var text = '' -var nodeName = '' -var lineNumber = -1 -var fileName = '' -var implicit = false -var meta = [] - -func _init(text, nodeName, lineNumber, fileName, implicit, meta): - self.text = text - self.nodeName = nodeName - self.fileName = fileName - self.implicit = implicit - self.meta = meta diff --git a/addons/Wol/core/program/node.gd b/addons/Wol/core/program/node.gd deleted file mode 100644 index b4871a3..0000000 --- a/addons/Wol/core/program/node.gd +++ /dev/null @@ -1,33 +0,0 @@ -extends Object - -var nodeName : String -var instructions : Array = [] -var labels : Dictionary -var tags: Array -var sourceId : String - -func _init(other = null): - if other != null && other.get_script() == self.get_script(): - nodeName = other.nodeName - instructions+=other.instructions - for key in other.labels.keys(): - labels[key] = other.labels[key] - tags += other.tags - sourceId = other.sourceId - -func equals(other)->bool: - - if other.get_script() != self.get_script(): - return false - if other.name != self.name: - return false - if other.instructions != self.instructions: - return false - if other.label != self.label: - return false - if other.sourceId != self.sourceId: - return false - return true - -func _to_string(): - return "Node[%s:%s]" % [nodeName,sourceId] diff --git a/addons/Wol/core/program/operand.gd b/addons/Wol/core/program/operand.gd deleted file mode 100644 index 93097fc..0000000 --- a/addons/Wol/core/program/operand.gd +++ /dev/null @@ -1,58 +0,0 @@ -extends Object - -enum ValueType{ - None, - StringValue, - BooleanValue, - FloatValue -} - -var value - -var type - -func _init(value): - if typeof(value) == TYPE_OBJECT && value.get_script() == self.get_script(): - #operand - self.set_value(value.value) - else: - set_value(value) - -func set_value(value): - match typeof(value): - TYPE_REAL,TYPE_INT: - set_number(value) - TYPE_BOOL: - set_boolean(value) - TYPE_STRING: - set_string(value) - _: - pass - -func set_boolean(value: bool): - _value(value) - type = ValueType.BooleanValue - return self - -func set_string(value:String): - _value(value) - type = ValueType.StringValue - return self - -func set_number(value:float): - _value(value) - type = ValueType.FloatValue - return self - -func clear_value(): - type = ValueType.None - value = null - -func clone(): - return get_script().new(self) - -func _to_string(): - return "Operand[%s:%s]" % [type,value] - -func _value(value): - self.value = value \ No newline at end of file diff --git a/addons/Wol/core/program/program.gd b/addons/Wol/core/program/program.gd deleted file mode 100644 index fbb4ecd..0000000 --- a/addons/Wol/core/program/program.gd +++ /dev/null @@ -1,22 +0,0 @@ -extends Node - -var programName = '' -var wolStrings = {} -var wolNodes = {} - -func get_node_tags(name): - return wolNodes[name].tags - -#possible support for line tags -func get_untagged_strings()->Dictionary: - return {} - -func merge(other): - pass - -func include(other): - pass - -func dump(library): - pass - diff --git a/addons/Wol/core/virtual_machine.gd b/addons/Wol/core/virtual_machine.gd index 9b9ac83..dc7b73c 100644 --- a/addons/Wol/core/virtual_machine.gd +++ b/addons/Wol/core/virtual_machine.gd @@ -1,4 +1,5 @@ extends Node + var WolGlobals = load("res://addons/Wol/autoloads/execution_states.gd") var FunctionInfo = load("res://addons/Wol/core/function_info.gd") @@ -43,11 +44,11 @@ func set_program(program): #return true if successeful false if no node #of that name found func set_node(name:String) -> bool: - if _program == null || _program.wolNodes.size() == 0: + if _program == null || _program.nodes.size() == 0: printerr("Could not load %s : no nodes loaded" % name) return false - if !_program.wolNodes.has(name): + if !_program.nodes.has(name): executionState = WolGlobals.ExecutionState.Stopped reset() printerr("No node named %s has been loaded" % name) @@ -55,7 +56,7 @@ func set_node(name:String) -> bool: _dialogue.dlog("Running node %s" % name) - _currentNode = _program.wolNodes[name] + _currentNode = _program.nodes[name] reset() _state.currentNodeName = name nodeStartHandler.call_func(name) diff --git a/project.godot b/project.godot index 9f78f8c..50b1a61 100644 --- a/project.godot +++ b/project.godot @@ -8,6 +8,28 @@ config_version=4 +_global_script_classes=[ { +"base": "Object", +"class": "Compiler", +"language": "GDScript", +"path": "res://addons/Wol/core/compiler/compiler.gd" +}, { +"base": "Node", +"class": "Wol", +"language": "GDScript", +"path": "res://addons/Wol/Wol.gd" +}, { +"base": "Object", +"class": "WolProgram", +"language": "GDScript", +"path": "res://addons/Wol/core/program.gd" +} ] +_global_script_class_icons={ +"Compiler": "", +"Wol": "", +"WolProgram": "" +} + [application] config/name="YarnSpinner"