refactored program.gd

This commit is contained in:
Bram Dingelstad 2021-11-20 13:18:44 +01:00
parent d5e515e4c1
commit 14f37f90c8
12 changed files with 200 additions and 220 deletions

View file

@ -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

View file

@ -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

View file

@ -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
#<String, LineInfo>
#<String, Program.Line>
var _stringTable : Dictionary = {}
var _stringCount : int = 0
#<int, WolGlobals.TokenType>
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)
_:

View file

@ -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()

124
addons/Wol/core/program.gd Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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"