improved a bunch of things (again)

This commit is contained in:
Bram Dingelstad 2021-11-20 22:29:24 +01:00
parent 611fc399ae
commit cda5fe8406
17 changed files with 409 additions and 430 deletions

View file

@ -1,7 +1,7 @@
extends Control extends Control
func _ready(): func _ready():
pass $VBoxContainer/ButtonTemplate.hide()
func continue_dialogue(): func continue_dialogue():
if $Tween.is_active(): if $Tween.is_active():
@ -12,7 +12,6 @@ func continue_dialogue():
$Wol.resume() $Wol.resume()
func _on_Wol_line(line): func _on_Wol_line(line):
print(var2str(line))
$RichTextLabel.text = line.text $RichTextLabel.text = line.text
$Tween.remove_all() $Tween.remove_all()
@ -27,9 +26,27 @@ func _on_Wol_line(line):
$Tween.start() $Tween.start()
func _on_Wol_options(options): func _on_Wol_options(options):
prints('got some options', options) var button_template = $VBoxContainer/ButtonTemplate
for option in options:
var button = button_template.duplicate()
button.text = option.line.text
button.name = 'Option%d' % option.id
$VBoxContainer.add_child(button)
button.connect('pressed', self, '_on_option_selected', [option])
button.show()
func _on_option_selected(option):
$Wol.select_option(option.id)
for child in $VBoxContainer.get_children():
if not 'Template' in child.name:
child.queue_free()
func _on_Wol_finished():
$RichTextLabel.text = ''
func _input(event): func _input(event):
if event is InputEventKey and event.scancode == KEY_ENTER and event.pressed: if event is InputEventKey and event.scancode == KEY_ENTER and event.pressed:
print('Pressed enter!')
continue_dialogue() continue_dialogue()

View file

@ -50,5 +50,6 @@ text = "This is a dialogue option"
[node name="Tween" type="Tween" parent="."] [node name="Tween" type="Tween" parent="."]
[connection signal="finished" from="Wol" to="." method="_on_Wol_finished"]
[connection signal="line" from="Wol" to="." method="_on_Wol_line"] [connection signal="line" from="Wol" to="." method="_on_Wol_line"]
[connection signal="options" from="Wol" to="." method="_on_Wol_options"] [connection signal="options" from="Wol" to="." method="_on_Wol_options"]

View file

@ -19,13 +19,13 @@ export(String, FILE, '*.wol,*.yarn') var path setget set_path
export(String) var start_node = 'Start' export(String) var start_node = 'Start'
export(bool) var auto_start = false export(bool) var auto_start = false
export(NodePath) var variable_storage_path export(NodePath) var variable_storage_path
export var auto_show_options = true
onready var variable_storage = get_node(variable_storage_path) onready var variable_storage = get_node(variable_storage_path)
var program var program
var dialogue var dialogue
var running = false
func _ready(): func _ready():
if Engine.editor_hint: if Engine.editor_hint:
@ -62,6 +62,7 @@ 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() var file = File.new()
file.open(_path, File.READ) file.open(_path, File.READ)
var source = file.get_as_text() var source = file.get_as_text()
@ -70,9 +71,11 @@ func set_path(_path):
path = _path path = _path
func _handle_line(line): func _handle_line(line):
var id = line.id call_deferred('emit_signal', 'line', line)
var string = program.strings[id] if auto_show_options \
call_deferred('emit_signal', 'line', string) and dialogue.get_vm().get_next_instruction().operation == Constants.ByteCode.AddOption:
return Constants.HandlerState.ContinueExecution
else:
return Constants.HandlerState.PauseExecution return Constants.HandlerState.PauseExecution
func _handle_command(command): func _handle_command(command):
@ -89,11 +92,9 @@ func _handle_options(options):
func _handle_dialogue_complete(): func _handle_dialogue_complete():
emit_signal('finished') emit_signal('finished')
running = false
func _handle_node_start(node): func _handle_node_start(node):
emit_signal('node_started', node) emit_signal('node_started', node)
print('node started')
dialogue.resume() dialogue.resume()
if !dialogue._visitedNodeCount.has(node): if !dialogue._visitedNodeCount.has(node):
@ -101,28 +102,23 @@ func _handle_node_start(node):
else: else:
dialogue._visitedNodeCount[node] += 1 dialogue._visitedNodeCount[node] += 1
print(dialogue._visitedNodeCount)
func _handle_node_complete(node): func _handle_node_complete(node):
emit_signal('node_completed', node) emit_signal('node_completed', node)
running = false
return Constants.HandlerState.ContinueExecution return Constants.HandlerState.ContinueExecution
func select_option(id): func select_option(id):
dialogue.get_vm().set_selected_option(id) dialogue.get_vm().set_selected_option(id)
resume()
func pause(): func pause():
dialogue.call_deferred('pause') dialogue.call_deferred('pause')
func start(node = start_node): func start(node = start_node):
if running:
return
init_dialogue() init_dialogue()
emit_signal('started') emit_signal('started')
running = true
dialogue.set_node(node) dialogue.set_node(node)
dialogue.start()
func resume(): func resume():
dialogue.call_deferred('resume') dialogue.call_deferred('resume')

View file

@ -72,6 +72,7 @@ static func compile_string(source: String, filename: String):
var value : String = result.get_string('value') var value : String = 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(' ','')])
title = value title = value
if(line_number >= source_lines.size() || source_lines[line_number] == '---'): if(line_number >= source_lines.size() || source_lines[line_number] == '---'):
@ -83,7 +84,7 @@ static func compile_string(source: String, filename: String):
#past header #past header
var body_lines : PoolStringArray = [] var body_lines : PoolStringArray = []
while line_number < source_lines.size() && 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
@ -91,10 +92,9 @@ static func compile_string(source: String, filename: String):
body = body_lines.join('\n') body = body_lines.join('\n')
var lexer = Lexer.new() var lexer = Lexer.new()
var tokens = lexer.tokenize(body, title, filename)
var tokens : Array = lexer.tokenize(body) var parser = Parser.new(tokens, title)
var parser = Parser.new(tokens)
var parser_node = parser.parse_node() var parser_node = parser.parse_node()
parser_node.name = title parser_node.name = title
@ -150,7 +150,7 @@ func compile_node(program, parsed_node):
if dangling_options: if dangling_options:
emit(Constants.ByteCode.ShowOptions, node_compiled) emit(Constants.ByteCode.ShowOptions, node_compiled)
emit(Constants.ByteCode.Run_node, node_compiled) emit(Constants.ByteCode.RunNode, node_compiled)
else: else:
emit(Constants.ByteCode.Stop, node_compiled) emit(Constants.ByteCode.Stop, node_compiled)
@ -269,11 +269,15 @@ func generate_shortcut_group(node,shortcut_group):
if option.condition != null : if option.condition != null :
endof_clause = register_label('conditional_%s'%option_count) endof_clause = register_label('conditional_%s'%option_count)
generate_expression(node,option.condition) generate_expression(node,option.condition)
emit(Constants.ByteCode.Jump_if_false,node,[Program.Operand.new(endof_clause)]) emit(Constants.ByteCode.JumpIfFalse, node, [Program.Operand.new(endof_clause)])
var label_line_id : String = ''#no tag TODO: ADD TAG SUPPORT var label_line_id = '' #TODO: Add tag support
var label_string_id : String = register_string(option.label,node.node_name, var label_string_id = register_string(
label_line_id,option.line_number,[]) option.label,
node.name,
label_line_id,option.line_number,
[]
)
emit(Constants.ByteCode.AddOption,node,[Program.Operand.new(label_string_id),Program.Operand.new(op_destination)]) emit(Constants.ByteCode.AddOption,node,[Program.Operand.new(label_string_id),Program.Operand.new(op_destination)])
@ -293,7 +297,7 @@ func generate_shortcut_group(node,shortcut_group):
if option.node != null : if option.node != null :
generate_block(node,option.node.statements) generate_block(node,option.node.statements)
emit(Constants.ByteCode.Jump_to,node,[Program.Operand.new(end)]) emit(Constants.ByteCode.JumpTo,node,[Program.Operand.new(end)])
option_count+=1 option_count+=1
#end of option group #end of option group
@ -323,10 +327,10 @@ func generate_if(node,if_statement):
if clause.expression!=null: if clause.expression!=null:
generate_expression(node,clause.expression) generate_expression(node,clause.expression)
emit(Constants.ByteCode.Jump_if_false,node,[Program.Operand.new(end_clause)]) emit(Constants.ByteCode.JumpIfFalse,node,[Program.Operand.new(end_clause)])
generate_block(node,clause.statements) generate_block(node,clause.statements)
emit(Constants.ByteCode.Jump_to,node,[Program.Operand.new(endif)]) emit(Constants.ByteCode.JumpTo,node,[Program.Operand.new(endif)])
if clause.expression!=null: if clause.expression!=null:
emit(Constants.ByteCode.Label,node,[Program.Operand.new(end_clause)]) emit(Constants.ByteCode.Label,node,[Program.Operand.new(end_clause)])
@ -348,7 +352,7 @@ func generate_option(node,option):
emit(Constants.ByteCode.RunNode,node,[Program.Operand.new(destination)]) emit(Constants.ByteCode.RunNode,node,[Program.Operand.new(destination)])
else : else :
var line_iD : String = ''#tags not supported TODO: ADD TAG SUPPORT var line_iD : String = ''#tags not supported TODO: ADD TAG SUPPORT
var string_iD = register_string(option.label,node.node_name,line_iD,option.line_number,[]) var string_iD = register_string(option.label,node.name,line_iD,option.line_number,[])
emit(Constants.ByteCode.AddOption,node,[Program.Operand.new(string_iD),Program.Operand.new(destination)]) emit(Constants.ByteCode.AddOption,node,[Program.Operand.new(string_iD),Program.Operand.new(destination)])
@ -357,13 +361,13 @@ func generate_option(node,option):
func generate_assignment(node,assignment): func generate_assignment(node,assignment):
# print('generating assign') # print('generating assign')
#assignment #assignment
if assignment.operation == Constants.TokenType.Equal_to_or_assign: if assignment.operation == Constants.TokenType.EqualToOrAssign:
#evaluate the expression to a value for the stack #evaluate the expression to a value for the stack
generate_expression(node,assignment.value) generate_expression(node,assignment.value)
else : else :
#this is combined op #this is combined op
#get value of var #get value of var
emit(Constants.ByteCode.Push_variable,node,[assignment.destination]) emit(Constants.ByteCode.PushVariable,node,[assignment.destination])
#evaluate the expression and push value to stack #evaluate the expression and push value to stack
generate_expression(node,assignment.value) generate_expression(node,assignment.value)
@ -371,16 +375,16 @@ func generate_assignment(node,assignment):
#stack contains oldvalue and result #stack contains oldvalue and result
match assignment.operation: match assignment.operation:
Constants.TokenType.Add_assign: Constants.TokenType.AddAssign:
emit(Constants.ByteCode.CallFunc,node, emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.Add))]) [Program.Operand.new(Constants.token_type_name(Constants.TokenType.Add))])
Constants.TokenType.Minus_assign: Constants.TokenType.MinusAssign:
emit(Constants.ByteCode.CallFunc,node, emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.Minus))]) [Program.Operand.new(Constants.token_type_name(Constants.TokenType.Minus))])
Constants.TokenType.Multiply_assign: Constants.TokenType.MultiplyAssign:
emit(Constants.ByteCode.CallFunc,node, emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.MultiplyAssign))]) [Program.Operand.new(Constants.token_type_name(Constants.TokenType.MultiplyAssign))])
Constants.TokenType.Divide_assign: Constants.TokenType.DivideAssign:
emit(Constants.ByteCode.CallFunc,node, emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.DivideAssign))]) [Program.Operand.new(Constants.token_type_name(Constants.TokenType.DivideAssign))])
_: _:
@ -388,7 +392,7 @@ func generate_assignment(node,assignment):
#stack contains destination value #stack contains destination value
#store the top of the stack in variable #store the top of the stack in variable
emit(Constants.ByteCode.Store_variable,node,[Program.Operand.new(assignment.destination)]) emit(Constants.ByteCode.StoreVariable,node,[Program.Operand.new(assignment.destination)])
#clean stack #clean stack
emit(Constants.ByteCode.Pop,node) emit(Constants.ByteCode.Pop,node)
@ -399,9 +403,9 @@ func generate_expression(node,expression):
# print('generating expression') # print('generating expression')
#expression = value || func call #expression = value || func call
match expression.type: match expression.type:
Constants.Expression_type.Value: Constants.ExpressionType.Value:
generate_value(node,expression.value) generate_value(node,expression.value)
Constants.Expression_type.Function_call: Constants.ExpressionType.FunctionCall:
#eval all parameters #eval all parameters
for param in expression.params: for param in expression.params:
generate_expression(node,param) generate_expression(node,param)
@ -422,8 +426,8 @@ func generate_value(node,value):
Constants.ValueType.Number: Constants.ValueType.Number:
emit(Constants.ByteCode.PushNumber,node,[Program.Operand.new(value.value.as_number())]) emit(Constants.ByteCode.PushNumber,node,[Program.Operand.new(value.value.as_number())])
Constants.ValueType.Str: Constants.ValueType.Str:
var id : String = register_string(value.value.as_string(), var id = register_string(value.value.as_string(),
node.node_name,'',value.line_number,[]) node.name,'',value.line_number,[])
emit(Constants.ByteCode.PushString,node,[Program.Operand.new(id)]) emit(Constants.ByteCode.PushString,node,[Program.Operand.new(id)])
Constants.ValueType.Boolean: Constants.ValueType.Boolean:
emit(Constants.ByteCode.PushBool,node,[Program.Operand.new(value.value.as_bool())]) emit(Constants.ByteCode.PushBool,node,[Program.Operand.new(value.value.as_bool())])

View file

@ -35,50 +35,50 @@ func _init():
func create_states(): func create_states():
var patterns : Dictionary = {} var patterns : Dictionary = {}
patterns[Constants.TokenType.Text] = '.*' patterns[Constants.TokenType.Text] = ['.*', 'any text']
patterns[Constants.TokenType.Number] = '\\-?[0-9]+(\\.[0-9+])?' patterns[Constants.TokenType.Number] = ['\\-?[0-9]+(\\.[0-9+])?', 'any number']
patterns[Constants.TokenType.Str] = '\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\'' patterns[Constants.TokenType.Str] = ['\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\'', 'any text']
patterns[Constants.TokenType.TagMarker] = '\\#' patterns[Constants.TokenType.TagMarker] = ['\\#', 'a tag #']
patterns[Constants.TokenType.LeftParen] = '\\(' patterns[Constants.TokenType.LeftParen] = ['\\(', 'left parenthesis (']
patterns[Constants.TokenType.RightParen] = '\\)' patterns[Constants.TokenType.RightParen] = ['\\)', 'right parenthesis )']
patterns[Constants.TokenType.EqualTo] = '(==|is(?!\\w)|eq(?!\\w))' patterns[Constants.TokenType.EqualTo] = ['(==|is(?!\\w)|eq(?!\\w))', '"=", "is" or "eq"']
patterns[Constants.TokenType.EqualToOrAssign] = '(=|to(?!\\w))' patterns[Constants.TokenType.EqualToOrAssign] = ['(=|to(?!\\w))', 'equal to "=" or assign "="']
patterns[Constants.TokenType.NotEqualTo] = '(\\!=|neq(?!\\w))' patterns[Constants.TokenType.NotEqualTo] = ['(\\!=|neq(?!\\w))', '"!=" or "neq"']
patterns[Constants.TokenType.GreaterThanOrEqualTo] = '(\\>=|gte(?!\\w))' patterns[Constants.TokenType.GreaterThanOrEqualTo] = ['(\\>=|gte(?!\\w))', '">=" or "gte"']
patterns[Constants.TokenType.GreaterThan] = '(\\>|gt(?!\\w))' patterns[Constants.TokenType.GreaterThan] = ['(\\>|gt(?!\\w))', '">" or "gt"']
patterns[Constants.TokenType.LessThanOrEqualTo] = '(\\<=|lte(?!\\w))' patterns[Constants.TokenType.LessThanOrEqualTo] = ['(\\<=|lte(?!\\w))', '"<=" or "lte"']
patterns[Constants.TokenType.LessThan] = '(\\<|lt(?!\\w))' patterns[Constants.TokenType.LessThan] = ['(\\<|lt(?!\\w))', '"<" or "lt"']
patterns[Constants.TokenType.AddAssign] = '\\+=' patterns[Constants.TokenType.AddAssign] = ['\\+=', '"+="']
patterns[Constants.TokenType.MinusAssign] = '\\-=' patterns[Constants.TokenType.MinusAssign] = ['\\-=', '"-="']
patterns[Constants.TokenType.MultiplyAssign] = '\\*=' patterns[Constants.TokenType.MultiplyAssign] = ['\\*=', '"*="']
patterns[Constants.TokenType.DivideAssign] = '\\/=' patterns[Constants.TokenType.DivideAssign] = ['\\/=', '"/="']
patterns[Constants.TokenType.Add] = '\\+' patterns[Constants.TokenType.Add] = ['\\+', '"+"']
patterns[Constants.TokenType.Minus] = '\\-' patterns[Constants.TokenType.Minus] = ['\\-', '"-"']
patterns[Constants.TokenType.Multiply] = '\\*' patterns[Constants.TokenType.Multiply] = ['\\*', '"*"']
patterns[Constants.TokenType.Divide] = '\\/' patterns[Constants.TokenType.Divide] = ['\\/', '"/"']
patterns[Constants.TokenType.Modulo] = '\\%' patterns[Constants.TokenType.Modulo] = ['\\%', '"%"']
patterns[Constants.TokenType.And] = '(\\&\\&|and(?!\\w))' patterns[Constants.TokenType.And] = ['(\\&\\&|and(?!\\w))', '"&&" or "and"']
patterns[Constants.TokenType.Or] = '(\\|\\||or(?!\\w))' patterns[Constants.TokenType.Or] = ['(\\|\\||or(?!\\w))', '"||" or "or"']
patterns[Constants.TokenType.Xor] = '(\\^|xor(?!\\w))' patterns[Constants.TokenType.Xor] = ['(\\^|xor(?!\\w))', '"^" or "xor"']
patterns[Constants.TokenType.Not] = '(\\!|not(?!\\w))' patterns[Constants.TokenType.Not] = ['(\\!|not(?!\\w))', '"!" or "not"']
patterns[Constants.TokenType.Variable] = '\\$([A-Za-z0-9_\\.])+' patterns[Constants.TokenType.Variable] = ['\\$([A-Za-z0-9_\\.])+', 'any variable']
patterns[Constants.TokenType.Comma] = '\\,' patterns[Constants.TokenType.Comma] = ['\\,', '","']
patterns[Constants.TokenType.TrueToken] = 'true(?!\\w)' patterns[Constants.TokenType.TrueToken] = ['true(?!\\w)', '"true"']
patterns[Constants.TokenType.FalseToken] = 'false(?!\\w)' patterns[Constants.TokenType.FalseToken] = ['false(?!\\w)', '"false"']
patterns[Constants.TokenType.NullToken] = 'null(?!\\w)' patterns[Constants.TokenType.NullToken] = ['null(?!\\w)', '"null"']
patterns[Constants.TokenType.BeginCommand] = '\\<\\<' patterns[Constants.TokenType.BeginCommand] = ['\\<\\<', 'beginning of a command "<<"']
patterns[Constants.TokenType.EndCommand] = '\\>\\>' patterns[Constants.TokenType.EndCommand] = ['\\>\\>', 'ending of a command ">>"']
patterns[Constants.TokenType.OptionStart] = '\\[\\[' patterns[Constants.TokenType.OptionStart] = ['\\[\\[', 'start of an option "[["']
patterns[Constants.TokenType.OptionEnd] = '\\]\\]' patterns[Constants.TokenType.OptionEnd] = ['\\]\\]', 'end of an option "]]"']
patterns[Constants.TokenType.OptionDelimit] = '\\|' patterns[Constants.TokenType.OptionDelimit] = ['\\|', 'middle of an option "|"']
patterns[Constants.TokenType.Identifier] = '[a-zA-Z0-9_:\\.]+' patterns[Constants.TokenType.Identifier] = ['[a-zA-Z0-9_:\\.]+', 'any reference to another node']
patterns[Constants.TokenType.IfToken] = 'if(?!\\w)' patterns[Constants.TokenType.IfToken] = ['if(?!\\w)', '"if"']
patterns[Constants.TokenType.ElseToken] = 'else(?!\\w)' patterns[Constants.TokenType.ElseToken] = ['else(?!\\w)', '"else"']
patterns[Constants.TokenType.ElseIf] = 'elseif(?!\\w)' patterns[Constants.TokenType.ElseIf] = ['elseif(?!\\w)', '"elseif"']
patterns[Constants.TokenType.EndIf] = 'endif(?!\\w)' patterns[Constants.TokenType.EndIf] = ['endif(?!\\w)', '"endif"']
patterns[Constants.TokenType.Set] = 'set(?!\\w)' patterns[Constants.TokenType.Set] = ['set(?!\\w)', '"set"']
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
@ -173,10 +173,7 @@ func create_states():
for stateKey in _states.keys(): for stateKey in _states.keys():
_states[stateKey].stateName = stateKey _states[stateKey].stateName = stateKey
pass func tokenize(text, title, filename):
func tokenize(text:String)->Array:
_indentStack.clear() _indentStack.clear()
_indentStack.push_front(IntBoolPair.new(0,false)) _indentStack.push_front(IntBoolPair.new(0,false))
_shouldTrackIndent = false _shouldTrackIndent = false
@ -191,17 +188,20 @@ func tokenize(text:String)->Array:
var line_number : int = 1 var line_number : int = 1
for line in lines: for line in lines:
tokens+=tokenize_line(line,line_number) tokens += tokenize_line(line, line_number, title, filename)
line_number += 1 line_number += 1
var endOfInput : Token = Token.new(Constants.TokenType.EndOfInput,_currentState,line_number,0) var endOfInput = Token.new(
Constants.TokenType.EndOfInput,
_currentState,
line_number,
0
)
tokens.append(endOfInput) tokens.append(endOfInput)
# print(tokens)
return tokens return tokens
func tokenize_line(line:String, line_number : int)->Array: func tokenize_line(line, line_number, title, filename):
var tokenStack : Array = [] var tokenStack : Array = []
var freshLine = line.replace('\t',' ').replace('\r','') var freshLine = line.replace('\t',' ').replace('\r','')
@ -214,7 +214,13 @@ func tokenize_line(line:String, line_number : int)->Array:
#we add an indenation token to record indent level #we add an indenation token to record indent level
_indentStack.push_front(IntBoolPair.new(indentation,true)) _indentStack.push_front(IntBoolPair.new(indentation,true))
var indent : Token = Token.new(Constants.TokenType.Indent,_currentState,line_number,prevIndentation.key) var indent : Token = Token.new(
Constants.TokenType.Indent,
_currentState,
filename,
line_number,
prevIndentation.key
)
indent.value = '%*s' % [indentation - prevIndentation.key,''] indent.value = '%*s' % [indentation - prevIndentation.key,'']
_shouldTrackIndent = false _shouldTrackIndent = false
@ -246,7 +252,7 @@ func tokenize_line(line:String, line_number : int)->Array:
var matched : bool = false var matched : bool = false
for rule in _currentState.rules: for rule in _currentState.rules:
var found : RegExMatch = rule.regex.search(freshLine, column) var found = rule.regex.search(freshLine, column)
if !found: if !found:
continue continue
@ -273,9 +279,9 @@ func tokenize_line(line:String, line_number : int)->Array:
# #
column = startIndex column = startIndex
var endIndex : int = found.get_start() + found.get_string().length() var end_index = found.get_start() + found.get_string().length()
tokenText = freshLine.substr(startIndex,endIndex-startIndex) tokenText = freshLine.substr(startIndex, end_index - startIndex)
else: else:
tokenText = found.get_string() tokenText = found.get_string()
@ -288,14 +294,20 @@ func tokenize_line(line:String, line_number : int)->Array:
tokenText = tokenText.replace('\\\\', '\\') tokenText = tokenText.replace('\\\\', '\\')
tokenText = tokenText.replace('\\\'','\'') tokenText = tokenText.replace('\\\'','\'')
var token : Token = Token.new(rule.tokenType,_currentState,line_number,column,tokenText) var token = Token.new(
rule.tokenType,
_currentState,
filename,
line_number,
column,
tokenText
)
token.delimitsText = rule.delimitsText token.delimitsText = rule.delimitsText
tokenStack.push_front(token) tokenStack.push_front(token)
if rule.enterState != null && rule.enterState.length() > 0: if rule.enterState != null and rule.enterState.length() > 0:
if not _states.has(rule.enterState):
if !_states.has(rule.enterState):
printerr('State[%s] not known - line(%s) col(%s)' % [rule.enterState, line_number, column]) printerr('State[%s] not known - line(%s) col(%s)' % [rule.enterState, line_number, column])
return [] return []
@ -308,12 +320,21 @@ func tokenize_line(line:String, line_number : int)->Array:
matched = true matched = true
break break
if !matched: if not matched:
# TODO: Send out some helpful messages var rules = []
printerr('expectedTokens [%s] - line(%s) col(%s)'%['refineErrors.Lexer.tokenize_line',line_number,column]) for rule in _currentState.rules:
return [] rules.append('"%s" (%s)' % [Constants.token_type_name(rule.tokenType), rule.human_readable_identifier])
var lastWhiteSpace : RegExMatch = whitespace.search(line,column) var error_data = [
PoolStringArray(rules).join(', ') if rules.size() == 1 else PoolStringArray(rules.slice(0, rules.size() - 2)).join(', ') + ' or %s' % rules[-1],
filename,
title,
line_number,
column
]
assert(false, 'Expected %s in file %s in node "%s" on line #%d (column #%d)' % error_data)
var lastWhiteSpace = whitespace.search(line, column)
if lastWhiteSpace: if lastWhiteSpace:
column += lastWhiteSpace.get_string().length() column += lastWhiteSpace.get_string().length()
@ -339,20 +360,22 @@ func enter_state(state:LexerState):
_shouldTrackIndent = true _shouldTrackIndent = true
class Token: class Token:
var type : int var type = -1
var value : String var value = ''
var line_number : int var filename = ''
var column : int var line_number = -1
var text : String var column = -1
var text = ''
var delimitsText : bool= false var delimitsText = false
var paramCount : int var paramCount = -1
var lexerState : String var lexerState = ''
func _init(type:int,state: LexerState, line_number:int = -1,column:int = -1,value:String =''): func _init(type, state, filename, line_number = -1, column = -1, value = ''):
self.type = type self.type = type
self.lexerState = state.stateName self.lexerState = state.stateName
self.filename = filename
self.line_number = line_number self.line_number = line_number
self.column = column self.column = column
self.value = value self.value = value
@ -360,7 +383,6 @@ class Token:
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]
class LexerState: class LexerState:
var stateName : String var stateName : String
@ -372,9 +394,9 @@ class LexerState:
self.patterns = patterns self.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] var pattern = '\\G%s' % patterns[type][0]
# print('pattern = %s' % pattern) # print('pattern = %s' % pattern)
var rule = Rule.new(type,pattern,state,delimitText) var rule = Rule.new(type, pattern, patterns[type][1], state, delimitText)
rules.append(rule) rules.append(rule)
return rule return rule
@ -409,16 +431,18 @@ class Rule:
var tokenType : int var tokenType : int
var isTextRule : bool var isTextRule : bool
var delimitsText : bool var delimitsText : bool
var human_readable_identifier = ''
func _init(type : int , regex : String, enterState : String, delimitsText:bool): func _init(type : int , regex : String, human_readable_identifier, enterState : String, delimitsText:bool):
self.tokenType = type self.tokenType = type
self.regex = RegEx.new() self.regex = RegEx.new()
self.regex.compile(regex) self.regex.compile(regex)
self.human_readable_identifier = human_readable_identifier
self.enterState = enterState self.enterState = enterState
self.delimitsText = delimitsText self.delimitsText = delimitsText
func _to_string(): func _to_string():
return '[Rule : %s - %s]' % [Constants.token_type_name(tokenType),regex] return '[Rule : %s (%s) - %s]' % [Constants.token_type_name(tokenType), human_readable_identifier, regex]
class IntBoolPair: class IntBoolPair:
var key : int var key : int

View file

@ -4,9 +4,11 @@ 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 = ''
func _init(tokens): func _init(tokens, title):
self._tokens = tokens self._tokens = tokens
self.title = title
enum Associativity { enum Associativity {
Left, Left,
@ -37,7 +39,7 @@ func expect_symbol(token_types = []):
if token_types.size() == 0: if token_types.size() == 0:
if token.type == Constants.TokenType.EndOfInput: if token.type == Constants.TokenType.EndOfInput:
printerr('Unexpected end of input.') assert(false, 'Unexpected end of input')
return null return null
return token return token
@ -45,8 +47,29 @@ func expect_symbol(token_types = []):
if token.type == type: if token.type == type:
return token return token
printerr('Unexpexted token: expected[ %s ] but got [ %s ]' % token_types + [token.type]) var token_names = []
return for type in token_types:
token_names.append(Constants.token_type_name(type))
var error_guess = '\n'
if Constants.token_type_name(token.type) == 'Identifier' \
and Constants.token_type_name(token_types[0]) == 'OptionEnd':
error_guess += 'Does the node your refer to have a space in it?'
else:
error_guess = ''
var error_data = [
token.filename,
title,
token.line_number,
token.column,
PoolStringArray(token_names).join(', '),
Constants.token_type_name(token.type),
error_guess
]
assert(false, '[%s|%s:%d:%d]:\nExpected token "%s" but got "%s"%s' % error_data)
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']
@ -55,12 +78,15 @@ func tokens():
return _tokens return _tokens
class ParseNode: class ParseNode:
var name = ''
var parent var parent
var line_number = -1 var line_number = -1
var tags = [] var tags = []
func _init(parent, parser): func _init(parent, parser):
self.parent = parent self.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
@ -77,7 +103,7 @@ class ParseNode:
func get_node_parent(): func get_node_parent():
var node = self var node = self
while node != null: while node != null:
if node.has_method('wol_node'): if node is ParseNode:
return node as WolNode return node as WolNode
node = node.parent node = node.parent
return null return null
@ -90,7 +116,6 @@ class ParseNode:
#this is a Wol Node - contains all the text #this is a Wol Node - contains all the text
class WolNode extends ParseNode: class WolNode extends ParseNode:
var name = ''
var source = '' var source = ''
var editor_node_tags = [] var editor_node_tags = []
@ -140,7 +165,7 @@ class Statement extends ParseNode:
elif Assignment.can_parse(parser): elif Assignment.can_parse(parser):
assignment = Assignment.new(self, parser) assignment = Assignment.new(self, parser)
type = Type.Assignment_statement type = Type.AssignmentStatement
elif ShortcutOptionGroup.can_parse(parser): elif ShortcutOptionGroup.can_parse(parser):
shortcut_option_group = ShortcutOptionGroup.new(self, parser) shortcut_option_group = ShortcutOptionGroup.new(self, parser)
@ -175,7 +200,7 @@ class Statement extends ParseNode:
info.append(block.tree_string(indent_level)) info.append(block.tree_string(indent_level))
Type.IfStatement: Type.IfStatement:
info.append(if_statement.tree_string(indent_level)) info.append(if_statement.tree_string(indent_level))
Type.Assignment_statement: Type.AssignmentStatement:
info.append(assignment.tree_string(indent_level)) info.append(assignment.tree_string(indent_level))
Type.OptionStatement: Type.OptionStatement:
info.append(option_statement.tree_string(indent_level)) info.append(option_statement.tree_string(indent_level))
@ -194,7 +219,7 @@ class CustomCommand extends ParseNode:
enum Type { enum Type {
Expression, Expression,
Client_command ClientCommand
} }
var type = -1 var type = -1
@ -215,21 +240,21 @@ class CustomCommand extends ParseNode:
#if first token is identifier and second is leftt parenthesis #if first token is identifier and second is leftt parenthesis
#evaluate as function #evaluate as function
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.Left_paren): && 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 = Expression_node.parse(self, p) var expression = ExpressionNode.parse(self, p)
type = Type.Expression type = Type.Expression
self.expression = expression self.expression = expression
else: else:
#otherwise evaluuate command #otherwise evaluuate command
type = Type.Client_command type = Type.ClientCommand
self.client_command = command_tokens[0].value self.client_command = command_tokens[0].value
func tree_string(indent_level): func tree_string(indent_level):
match type: match type:
Type.Expression: Type.Expression:
return tab(indent_level,'Expression: %s'% expression.tree_string(indent_level+1)) return tab(indent_level,'Expression: %s'% expression.tree_string(indent_level+1))
Type.Client_command: Type.ClientCommand:
return tab(indent_level,'Command: %s' % client_command) return tab(indent_level,'Command: %s' % client_command)
return '' return ''
@ -246,10 +271,10 @@ class ShortcutOptionGroup extends ParseNode:
# expect one otherwise invalid # expect one otherwise invalid
var index = 1 var index = 1
options.append(Short_cut_option.new(index, self, parser)) options.append(ShortCutOption.new(index, self, parser))
index += 1 index += 1
while parser.next_symbol_is([Constants.TokenType.ShortcutOption]): while parser.next_symbol_is([Constants.TokenType.ShortcutOption]):
options.append(Short_cut_option.new(index, self, parser)) options.append(ShortCutOption.new(index, self, parser))
index += 1 index += 1
func tree_string(indent_level): func tree_string(indent_level):
@ -267,7 +292,7 @@ class ShortcutOptionGroup extends ParseNode:
static func can_parse(parser): static func can_parse(parser):
return parser.next_symbol_is([Constants.TokenType.ShortcutOption]) return parser.next_symbol_is([Constants.TokenType.ShortcutOption])
class Short_cut_option extends ParseNode: class ShortCutOption extends ParseNode:
var label = '' var label = ''
var condition var condition
var node var node
@ -285,7 +310,7 @@ class Short_cut_option extends ParseNode:
if parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.IfToken]): if parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.IfToken]):
parser.expect_symbol([Constants.TokenType.BeginCommand]) parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.IfToken]) parser.expect_symbol([Constants.TokenType.IfToken])
condition = Expression_node.parse(self, parser) condition = ExpressionNode.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand]) parser.expect_symbol([Constants.TokenType.EndCommand])
elif parser.next_symbol_is([Constants.TokenType.TagMarker]): elif parser.next_symbol_is([Constants.TokenType.TagMarker]):
@ -299,7 +324,7 @@ class Short_cut_option extends ParseNode:
if parser.next_symbol_is([Constants.TokenType.Indent]): if parser.next_symbol_is([Constants.TokenType.Indent]):
parser.expect_symbol([Constants.TokenType.Indent]) parser.expect_symbol([Constants.TokenType.Indent])
node = WolNode.new('%s.%s' %[self.get_node_parent().name , index], self, parser) node = WolNode.new('%s.%s' % [parent.name, index], self, parser)
parser.expect_symbol([Constants.TokenType.Dedent]) parser.expect_symbol([Constants.TokenType.Dedent])
@ -359,7 +384,6 @@ class OptionStatement extends ParseNode:
var label = '' var label = ''
func _init(parent, parser).(parent, parser): func _init(parent, parser).(parent, parser):
var strings = [] var strings = []
# NOTE: parse [[LABEL # NOTE: parse [[LABEL
@ -397,14 +421,14 @@ class IfStatement extends ParseNode:
parser.expect_symbol([Constants.TokenType.BeginCommand]) parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.IfToken]) parser.expect_symbol([Constants.TokenType.IfToken])
prime.expression = Expression_node.parse(self, parser) prime.expression = ExpressionNode.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand]) parser.expect_symbol([Constants.TokenType.EndCommand])
#read statements until 'endif' or 'else' or 'else if' #read statements until 'endif' or 'else' or 'else if'
var statements = []#statement var statements = []#statement
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.End_if]) \ while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.EndIf]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_token]) \ and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseToken]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_if]): and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseIf]):
statements.append(Statement.new(self, parser)) statements.append(Statement.new(self, parser))
@ -416,20 +440,20 @@ class IfStatement extends ParseNode:
clauses.append(prime) clauses.append(prime)
#handle all else if #handle all else if
while parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_if]): while parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseIf]):
var clause_elif = Clause.new() var clause_elif = Clause.new()
#parse condition syntax #parse condition syntax
parser.expect_symbol([Constants.TokenType.BeginCommand]) parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.Else_if]) parser.expect_symbol([Constants.TokenType.ElseIf])
clause_elif.expression = Expression_node.parse(self, parser) clause_elif.expression = ExpressionNode.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand]) parser.expect_symbol([Constants.TokenType.EndCommand])
var elif_statements = []#statement var elif_statements = []#statement
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.End_if]) \ while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.EndIf]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_token]) \ and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseToken]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_if]): and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseIf]):
elif_statements.append(Statement.new(self, parser)) elif_statements.append(Statement.new(self, parser))
@ -442,17 +466,17 @@ class IfStatement extends ParseNode:
#handle else if exists #handle else if exists
if (parser.next_symbols_are([Constants.TokenType.BeginCommand, if (parser.next_symbols_are([Constants.TokenType.BeginCommand,
Constants.TokenType.Else_token, Constants.TokenType.EndCommand])): Constants.TokenType.ElseToken, Constants.TokenType.EndCommand])):
#expect no expression - just <<else>> #expect no expression - just <<else>>
parser.expect_symbol([Constants.TokenType.BeginCommand]) parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.Else_token]) parser.expect_symbol([Constants.TokenType.ElseToken])
parser.expect_symbol([Constants.TokenType.EndCommand]) parser.expect_symbol([Constants.TokenType.EndCommand])
#parse until hit endif #parse until hit endif
var clause_else = Clause.new() var clause_else = Clause.new()
var el_statements = []#statement var el_statements = []#statement
while !parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.End_if]): while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.EndIf]):
el_statements.append(Statement.new(self, parser)) el_statements.append(Statement.new(self, parser))
clause_else.statements = el_statements clause_else.statements = el_statements
@ -464,7 +488,7 @@ class IfStatement extends ParseNode:
#finish #finish
parser.expect_symbol([Constants.TokenType.BeginCommand]) parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.End_if]) parser.expect_symbol([Constants.TokenType.EndIf])
parser.expect_symbol([Constants.TokenType.EndCommand]) parser.expect_symbol([Constants.TokenType.EndCommand])
@ -488,7 +512,7 @@ class IfStatement extends ParseNode:
return parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.IfToken]) return parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.IfToken])
pass pass
class Value_node extends ParseNode: class ValueNode extends ParseNode:
const Value = preload('res://addons/Wol/core/value.gd') const Value = preload('res://addons/Wol/core/value.gd')
const Lexer = preload('res://addons/Wol/core/compiler/lexer.gd') const Lexer = preload('res://addons/Wol/core/compiler/lexer.gd')
var value var value
@ -508,15 +532,15 @@ class Value_node extends ParseNode:
value = Value.new(float(token.value)) value = Value.new(float(token.value))
Constants.TokenType.Str: Constants.TokenType.Str:
value = Value.new(token.value) value = Value.new(token.value)
Constants.TokenType.False_token: Constants.TokenType.FalseToken:
value = Value.new(false) value = Value.new(false)
Constants.TokenType.True_token: Constants.TokenType.TrueToken:
value = Value.new(true) value = Value.new(true)
Constants.TokenType.Variable: Constants.TokenType.Variable:
value = Value.new(null) value = Value.new(null)
value.type = Constants.Value_type.Variable value.type = Constants.ValueType.Variable
value.variable = token.value value.variable = token.value
Constants.TokenType.Null_token: Constants.TokenType.NullToken:
value = Value.new(null) value = Value.new(null)
_: _:
printerr('%s, Invalid token type' % token.name) printerr('%s, Invalid token type' % token.name)
@ -529,33 +553,32 @@ class Value_node extends ParseNode:
# math (1 + 2 - 5 * 3 / 10 % 2) # math (1 + 2 - 5 * 3 / 10 % 2)
# Identifiers # Identifiers
# Values # Values
class Expression_node extends ParseNode: class ExpressionNode extends ParseNode:
var type var type
var value var value
var function var function
var params = []#Expression_node var params = []#ExpressionNode
func _init(parent, parser, value, function = '', params = []).(parent, parser): func _init(parent, parser, value, function = '', params = []).(parent, parser):
#no function - means value #no function - means value
if value != null: if value != null:
self.type = Constants.Expression_type.Value self.type = Constants.ExpressionType.Value
self.value = value self.value = value
else:#function else:#function
self.type = Constants.Expression_type.Function_call self.type = Constants.ExpressionType.FunctionCall
self.function = function self.function = function
self.params = params self.params = params
func tree_string(indent_level): func tree_string(indent_level):
var info = [] var info = []
match type: match type:
Constants.Expression_type.Value: Constants.ExpressionType.Value:
return value.tree_string(indent_level) return value.tree_string(indent_level)
Constants.Expression_type.Function_call: Constants.ExpressionType.FunctionCall:
info.append(tab(indent_level,'Func[%s - params(%s)]:{'%[function, params.size()])) info.append(tab(indent_level,'Func[%s - params(%s)]:{'%[function, params.size()]))
for param in params: for param in params:
#print('----> %s param_size:%s'%[(function) , params.size()])
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,'}'))
@ -575,13 +598,13 @@ class Expression_node extends ParseNode:
Constants.TokenType.Number, Constants.TokenType.Number,
Constants.TokenType.Variable, Constants.TokenType.Variable,
Constants.TokenType.Str, Constants.TokenType.Str,
Constants.TokenType.Left_paren, Constants.TokenType.LeftParen,
Constants.TokenType.Right_paren, Constants.TokenType.RightParen,
Constants.TokenType.Identifier, Constants.TokenType.Identifier,
Constants.TokenType.Comma, Constants.TokenType.Comma,
Constants.TokenType.True_token, Constants.TokenType.TrueToken,
Constants.TokenType.False_token, Constants.TokenType.FalseToken,
Constants.TokenType.Null_token Constants.TokenType.NullToken
] ]
valid_types += Operator.op_types() valid_types += Operator.op_types()
valid_types.invert() valid_types.invert()
@ -595,9 +618,9 @@ class Expression_node extends ParseNode:
if next.type == Constants.TokenType.Variable \ if next.type == Constants.TokenType.Variable \
or next.type == Constants.TokenType.Number \ or next.type == Constants.TokenType.Number \
or next.type == Constants.TokenType.Str \ or next.type == Constants.TokenType.Str \
or next.type == Constants.TokenType.False_token \ or next.type == Constants.TokenType.FalseToken \
or next.type == Constants.TokenType.True_token \ or next.type == Constants.TokenType.TrueToken \
or next.type == Constants.TokenType.Null_token: or next.type == Constants.TokenType.NullToken:
#output primitives #output primitives
rpn.append(next) rpn.append(next)
@ -606,12 +629,12 @@ class Expression_node extends ParseNode:
func_stack.push_back(next) func_stack.push_back(next)
#next token is parent - left #next token is parent - left
next = parser.expect_symbol([Constants.TokenType.Left_paren]) next = parser.expect_symbol([Constants.TokenType.LeftParen])
op_stack.push_back(next) op_stack.push_back(next)
elif next.type == Constants.TokenType.Comma: elif next.type == Constants.TokenType.Comma:
#resolve sub expression before moving on #resolve sub expression before moving on
while op_stack.back().type != Constants.TokenType.Left_paren: while op_stack.back().type != Constants.TokenType.LeftParen:
var p = op_stack.pop_back() var p = op_stack.pop_back()
if p == null: if p == null:
printerr('unbalanced parenthesis %s ' % next.name) printerr('unbalanced parenthesis %s ' % next.name)
@ -621,7 +644,7 @@ class Expression_node extends ParseNode:
#next token in op_stack left paren #next token in op_stack left paren
# next parser token not allowed to be right paren or comma # next parser token not allowed to be right paren or comma
if parser.next_symbol_is([Constants.TokenType.Right_paren, 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)
@ -643,34 +666,33 @@ class Expression_node extends ParseNode:
if next.type == Constants.TokenType.Minus: if next.type == Constants.TokenType.Minus:
if last == null \ if last == null \
or last.type == Constants.TokenType.Left_paren \ or last.type == Constants.TokenType.LeftParen \
or Operator.is_op(last.type): or Operator.is_op(last.type):
#unary minus #unary minus
next.type = Constants.TokenType.Unary_minus next.type = Constants.TokenType.UnaryMinus
#cannot assign inside expression #cannot assign inside expression
# x = a is the same as x == a # x = a is the same as x == a
if next.type == Constants.TokenType.EqualToOrAssign: if next.type == Constants.TokenType.EqualToOrAssign:
next.type = Constants.TokenType.EqualTo next.type = Constants.TokenType.EqualTo
#operator precedence #operator precedence
while (Expression_node.is_apply_precedence(next.type, op_stack)): while (ExpressionNode.is_apply_precedence(next.type, op_stack)):
var op = op_stack.pop_back() var op = op_stack.pop_back()
rpn.append(op) rpn.append(op)
op_stack.push_back(next) op_stack.push_back(next)
elif next.type == Constants.TokenType.Left_paren: elif next.type == Constants.TokenType.LeftParen:
#entered parenthesis sub expression #entered parenthesis sub expression
op_stack.push_back(next) op_stack.push_back(next)
elif next.type == Constants.TokenType.Right_paren: elif next.type == Constants.TokenType.RightParen:
#leaving sub expression #leaving sub expression
# resolve order of operations # resolve order of operations
while op_stack.back().type != Constants.TokenType.Left_paren: while op_stack.back().type != Constants.TokenType.LeftParen:
rpn.append(op_stack.pop_back()) rpn.append(op_stack.pop_back())
if op_stack.back() == null: if op_stack.back() == null:
printerr('Unbalanced parenthasis #Right_paren. Parser.Expression_node') printerr('Unbalanced parenthasis #RightParen. Parser.ExpressionNode')
op_stack.pop_back() op_stack.pop_back()
@ -679,7 +701,7 @@ class Expression_node extends ParseNode:
#last token == left paren this == no params #last token == left paren this == no params
#else #else
#we have more than 1 param #we have more than 1 param
if last.type != Constants.TokenType.Left_paren: if last.type != Constants.TokenType.LeftParen:
func_stack.back().param_count+=1 func_stack.back().param_count+=1
rpn.append(op_stack.pop_back()) rpn.append(op_stack.pop_back())
@ -698,10 +720,9 @@ class Expression_node extends ParseNode:
#build expression tree #build expression tree
var first = rpn.front() var first = rpn.front()
var eval_stack = []#Expression_node var eval_stack = []#ExpressionNode
while rpn.size() > 0: while rpn.size() > 0:
var next = rpn.pop_front() var next = rpn.pop_front()
if Operator.is_op(next.type): if Operator.is_op(next.type):
#operation #operation
@ -710,7 +731,7 @@ class Expression_node 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 = []#Expression_node var params = []#ExpressionNode
for i in range(info.arguments): for i in range(info.arguments):
params.append(eval_stack.pop_back()) params.append(eval_stack.pop_back())
@ -718,7 +739,7 @@ class Expression_node extends ParseNode:
var function = get_func_name(next.type) var function = get_func_name(next.type)
var expression = Expression_node.new(parent, parser, null, function, params) var expression = ExpressionNode.new(parent, parser, null, function, params)
eval_stack.append(expression) eval_stack.append(expression)
@ -727,19 +748,19 @@ class Expression_node extends ParseNode:
var function = next.value var function = next.value
var params = []#Expression_node var params = []#ExpressionNode
for i in range(next.param_count): for i in range(next.param_count):
params.append(eval_stack.pop_back()) params.append(eval_stack.pop_back())
params.invert() params.invert()
var expression = Expression_node.new(parent, parser, null, function, params) var expression = ExpressionNode.new(parent, parser, null, function, params)
eval_stack.append(expression) eval_stack.append(expression)
else: #raw value else: #raw value
var value = Value_node.new(parent, parser, next) var value = ValueNode.new(parent, parser, next)
var expression = Expression_node.new(parent, parser, value) var expression = ExpressionNode.new(parent, parser, value)
eval_stack.append(expression) eval_stack.append(expression)
@ -796,7 +817,7 @@ class Assignment extends ParseNode:
parser.expect_symbol([Constants.TokenType.Set]) parser.expect_symbol([Constants.TokenType.Set])
destination = parser.expect_symbol([Constants.TokenType.Variable]).value destination = parser.expect_symbol([Constants.TokenType.Variable]).value
operation = parser.expect_symbol(Assignment.valid_ops()).type operation = parser.expect_symbol(Assignment.valid_ops()).type
value = Expression_node.parse(self, parser) value = ExpressionNode.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand]) parser.expect_symbol([Constants.TokenType.EndCommand])
func tree_string(indent_level): func tree_string(indent_level):
@ -817,10 +838,10 @@ class Assignment extends ParseNode:
static func valid_ops(): static func valid_ops():
return [ return [
Constants.TokenType.EqualToOrAssign, Constants.TokenType.EqualToOrAssign,
Constants.TokenType.Add_assign, Constants.TokenType.AddAssign,
Constants.TokenType.Minus_assign, Constants.TokenType.MinusAssign,
Constants.TokenType.Divide_assign, Constants.TokenType.DivideAssign,
Constants.TokenType.Multiply_assign Constants.TokenType.MultiplyAssign
] ]
class Operator extends ParseNode: class Operator extends ParseNode:
@ -848,22 +869,22 @@ class Operator extends ParseNode:
var TokenType = Constants.TokenType var TokenType = Constants.TokenType
match op: match op:
TokenType.Not, TokenType.Unary_minus: TokenType.Not, TokenType.UnaryMinus:
return Operator_info.new(Associativity.Right, 30, 1) return OperatorInfo.new(Associativity.Right, 30, 1)
TokenType.Multiply, TokenType.Divide, TokenType.Modulo: TokenType.Multiply, TokenType.Divide, TokenType.Modulo:
return Operator_info.new(Associativity.Left, 20, 2) return OperatorInfo.new(Associativity.Left, 20, 2)
TokenType.Add, TokenType.Minus: TokenType.Add, TokenType.Minus:
return Operator_info.new(Associativity.Left, 15, 2) return OperatorInfo.new(Associativity.Left, 15, 2)
TokenType.GreaterThan, TokenType.LessThan, TokenType.GreaterThanOrEqualTo, TokenType.LessThanOrEqualTo: TokenType.GreaterThan, TokenType.LessThan, TokenType.GreaterThanOrEqualTo, TokenType.LessThanOrEqualTo:
return Operator_info.new(Associativity.Left, 10, 2) return OperatorInfo.new(Associativity.Left, 10, 2)
TokenType.EqualTo, TokenType.EqualToOrAssign, TokenType.NotEqualTo: TokenType.EqualTo, TokenType.EqualToOrAssign, TokenType.NotEqualTo:
return Operator_info.new(Associativity.Left, 5, 2) return OperatorInfo.new(Associativity.Left, 5, 2)
TokenType.And: TokenType.And:
return Operator_info.new(Associativity.Left, 4, 2) return OperatorInfo.new(Associativity.Left, 4, 2)
TokenType.Or: TokenType.Or:
return Operator_info.new(Associativity.Left, 3, 2) return OperatorInfo.new(Associativity.Left, 3, 2)
TokenType.Xor: TokenType.Xor:
return Operator_info.new(Associativity.Left, 2, 2) return OperatorInfo.new(Associativity.Left, 2, 2)
_: _:
printerr('Unknown operator: %s' % op.name) printerr('Unknown operator: %s' % op.name)
return null return null
@ -874,7 +895,7 @@ class Operator extends ParseNode:
static func op_types(): static func op_types():
return [ return [
Constants.TokenType.Not, Constants.TokenType.Not,
Constants.TokenType.Unary_minus, Constants.TokenType.UnaryMinus,
Constants.TokenType.Add, Constants.TokenType.Add,
Constants.TokenType.Minus, Constants.TokenType.Minus,
@ -897,7 +918,7 @@ class Operator extends ParseNode:
] ]
class Operator_info: class OperatorInfo:
var associativity var associativity
var precedence = -1 var precedence = -1
var arguments = -1 var arguments = -1

View file

@ -198,3 +198,9 @@ static func bytecode_name(bytecode):
'Stop', 'Stop',
'RunNode' 'RunNode'
][bytecode] ][bytecode]
static func token_name(type):
for key in TokenType.keys():
if TokenType[key] == type:
return key
return ''

View file

@ -1,7 +1,6 @@
extends Node extends Node
const DEFAULT_START = 'Start' const DEFAULT_START = 'Start'
const FMF_PLACEHOLDE = '<VALUE PLACEHOLDER>'
const Constants = preload('res://addons/Wol/core/constants.gd') const Constants = preload('res://addons/Wol/core/constants.gd')
const StandardLibrary = preload('res://addons/Wol/core/libraries/standard.gd') const StandardLibrary = preload('res://addons/Wol/core/libraries/standard.gd')
@ -11,24 +10,19 @@ const Value = preload('res://addons/Wol/core/value.gd')
var _variableStorage var _variableStorage
var _debugLog
var _errLog
var _program var _program
var library var library
var _vm : VirtualMachine var _vm
var _visitedNodeCount : Dictionary = {} var _visitedNodeCount = {}
var executionComplete : bool var executionComplete
func _init(variableStorage): func _init(variableStorage):
_variableStorage = variableStorage _variableStorage = variableStorage
_vm = VirtualMachine.new(self) _vm = VirtualMachine.new(self)
library = WolLibrary.new() library = WolLibrary.new()
_debugLog = funcref(self, 'dlog')
_errLog = funcref(self, 'elog')
executionComplete = false executionComplete = false
# import the standard library # import the standard library
@ -41,13 +35,6 @@ func _init(variableStorage):
#add function to lib that gets the node visit count #add function to lib that gets the node visit count
library.register_function('visit_count', -1, funcref(self, 'node_visit_count'), true) library.register_function('visit_count', -1, funcref(self, 'node_visit_count'), true)
func dlog(message:String):
print('YARN_DEBUG : %s' % message)
func elog(message:String):
print('YARN_ERROR : %s' % message)
func is_active(): func is_active():
return get_exec_state() != Constants.ExecutionState.Stopped return get_exec_state() != Constants.ExecutionState.Stopped
@ -55,15 +42,19 @@ func is_active():
func get_exec_state(): func get_exec_state():
return _vm.executionState return _vm.executionState
func set_selected_option(option:int): func set_selected_option(option):
_vm.set_selected_option(option) _vm.set_selected_option(option)
func set_node(name:String = DEFAULT_START): func set_node(name = DEFAULT_START):
_vm.set_node(name) _vm.set_node(name)
func start():
if _vm.executionState == Constants.ExecutionState.Stopped:
_vm.resume()
func resume(): func resume():
if _vm.executionState == Constants.ExecutionState.Running: if _vm.executionState == Constants.ExecutionState.Running \
print('BLOCKED') or _vm.executionState == Constants.ExecutionState.Stopped:
return return
_vm.resume() _vm.resume()
@ -81,12 +72,10 @@ func current_node():
func get_node_id(name): func get_node_id(name):
if _program.nodes.size() == 0: if _program.nodes.size() == 0:
_errLog.call_func('No nodes loaded')
return '' return ''
if _program.nodes.has(name): if _program.nodes.has(name):
return 'id:'+name return 'id:'+name
else: else:
_errLog.call_func('No node named [%s] exists' % name)
return '' return ''
func unloadAll(clear_visited:bool = true): func unloadAll(clear_visited:bool = true):
@ -116,7 +105,7 @@ func is_node_visited(node = _vm.current_node_name()):
func node_visit_count(node = _vm.current_node_name()): func node_visit_count(node = _vm.current_node_name()):
if node is Value: if node is Value:
node = _program.wolStrings[node.value()].text node = _program.strings[node.value()].text
var visitCount : int = 0 var visitCount : int = 0
if _visitedNodeCount.has(node): if _visitedNodeCount.has(node):

View file

@ -1,6 +0,0 @@
extends Object
var command : String
func _init(command : String):
self.command = command

View file

@ -1,16 +0,0 @@
extends Node
# Declare member variables here. Examples:
# var a = 2
# var b = "text"
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

View file

@ -1,8 +0,0 @@
extends Object
# class_name DialogueLine
var id = ''
var substitutions = []
func _init(id):
self.id = id

View file

@ -1,13 +0,0 @@
extends Object
const Line = preload("res://addons/Wol/core/dialogue/line.gd")
var line : Line
var id : int
var destination : String
func _init(line : Line,id : int, destination: String):
self.line = line
self.id = id
self.destination = destination

View file

@ -1,69 +1,69 @@
extends "res://addons/Wol/core/library.gd" extends 'res://addons/Wol/core/library.gd'
const Value = preload("res://addons/Wol/core/value.gd") const Value = preload('res://addons/Wol/core/value.gd')
func _init(): func _init():
register_function("Add",2,funcref(self,"add"),true) register_function('Add', 2, funcref(self, 'add'), true)
register_function("Minus",2,funcref(self,"sub"),true) register_function('Minus', 2, funcref(self, 'sub'), true)
register_function("UnaryMinus",1,funcref(self,"unary_minus"),true) register_function('UnaryMinus', 1, funcref(self, 'unary_minus'), true)
register_function("Divide",2,funcref(self,"div"),true) register_function('Divide', 2, funcref(self, 'div'), true)
register_function("Multiply",2,funcref(self,"mul"),true) register_function('Multiply', 2, funcref(self, 'mul'), true)
register_function("Modulo",2,funcref(self,"mod"),true) register_function('Modulo', 2, funcref(self, 'mod'), true)
register_function("EqualTo",2,funcref(self,"equal"),true) register_function('EqualTo', 2, funcref(self, 'equal'), true)
register_function("NotEqualTo",2,funcref(self,"noteq"),true) register_function('NotEqualTo', 2, funcref(self, 'noteq'), true)
register_function("GreaterThan",2,funcref(self,"ge"),true) register_function('GreaterThan', 2, funcref(self, 'ge'), true)
register_function("GreaterThanOrEqualTo",2,funcref(self,"geq"),true) register_function('GreaterThanOrEqualTo', 2, funcref(self, 'geq'), true)
register_function("LessThan",2,funcref(self,"le"),true) register_function('LessThan', 2, funcref(self, 'le'), true)
register_function("LessThanOrEqualTo",2,funcref(self,"leq"),true) register_function('LessThanOrEqualTo', 2, funcref(self, 'leq'), true)
register_function("And",2,funcref(self,"land"),true) register_function('And', 2, funcref(self, 'land'), true)
register_function("Or",2,funcref(self,"lor"),true) register_function('Or', 2, funcref(self, 'lor'), true)
register_function("Xor",2,funcref(self,"xor"),true) register_function('Xor', 2, funcref(self, 'xor'), true)
register_function("Not",1,funcref(self,"lnot"),true) register_function('Not', 1, funcref(self, 'lnot'), true)
func add(param1:Value,param2:Value): func add(param1, param2):
return param1.add(param2) return param1.add(param2)
func sub(param1:Value,param2:Value): func sub(param1, param2):
return param1.sub(param2) return param1.sub(param2)
func unary_minus(param1:Value): func unary_minus(param1):
return param1.negative() return param1.negative()
func div(param1:Value,param2:Value): func div(param1, param2):
return param1.div(param2) return param1.div(param2)
func mul(param1:Value,param2:Value): func mul(param1, param2):
return param1.mult(param2) return param1.mult(param2)
func mod(param1:Value,param2:Value): func mod(param1, param2):
return param1.mod(param2) return param1.mod(param2)
func equal(param1:Value,param2:Value): func equal(param1, param2):
return param1.equals(param2) return param1.equals(param2)
func noteq(param1:Value,param2:Value): func noteq(param1, param2):
return !param1.equals(param2) return !param1.equals(param2)
func ge(param1:Value,param2:Value): func ge(param1, param2):
return param1.greater(param2) return param1.greater(param2)
func geq(param1:Value,param2:Value): func geq(param1, param2):
return param1.geq(param2) return param1.geq(param2)
func le(param1:Value,param2:Value): func le(param1, param2):
return param1.less(param2) return param1.less(param2)
func leq(param1:Value,param2:Value): func leq(param1, param2):
return param1.leq(param2) return param1.leq(param2)
func land(param1:Value,param2:Value): func land(param1, param2):
return param1.as_bool() && param2.as_bool() return param1.as_bool() and param2.as_bool()
func lor(param1:Value,param2:Value): func lor(param1, param2):
return param1.as_bool() || param2.as_bool() return param1.as_bool() or param2.as_bool()
func xor(param1:Value,param2:Value): func xor(param1, param2):
return param1.as_bool() != param2.as_bool() return param1.as_bool() != param2.as_bool()
func lnot(param1:Value): func lnot(param1):
return !param1.as_bool() return not param1.as_bool()

View file

@ -22,6 +22,22 @@ class Line:
self.implicit = implicit self.implicit = implicit
self.meta = meta self.meta = meta
class Option:
var line
var id = -1
var destination = ''
func _init(line, id, destination):
self.line = line
self.id = id
self.destination = destination
class Command:
var command = ''
func _init(command):
self.command = command
class WolNode: class WolNode:
var name = '' var name = ''
var instructions = [] var instructions = []

View file

@ -1,15 +1,7 @@
extends Node extends Node
const Constants = preload('res://addons/Wol/core/constants.gd') const Constants = preload('res://addons/Wol/core/constants.gd')
var FunctionInfo = load('res://addons/Wol/core/function_info.gd')
var Value = load('res://addons/Wol/core/value.gd') var Value = load('res://addons/Wol/core/value.gd')
var WolProgram = load('res://addons/Wol/core/program/program.gd')
var WolNode = load('res://addons/Wol/core/program/wol_node.gd')
var Instruction = load('res://addons/Wol/core/program/instruction.gd')
var Line = load('res://addons/Wol/core/dialogue/line.gd')
var Command = load('res://addons/Wol/core/dialogue/command.gd')
var Option = load('res://addons/Wol/core/dialogue/option.gd')
const EXECUTION_COMPLETE : String = 'execution_complete_command' const EXECUTION_COMPLETE : String = 'execution_complete_command'
@ -54,15 +46,12 @@ func set_node(name:String) -> bool:
printerr('No node named %s has been loaded' % name) printerr('No node named %s has been loaded' % name)
return false return false
_dialogue.dlog('Running node %s' % name)
_currentNode = _program.nodes[name] _currentNode = _program.nodes[name]
reset() reset()
_state.currentNodeName = name _state.currentNodeName = name
nodeStartHandler.call_func(name) nodeStartHandler.call_func(name)
return true return true
func current_node_name()->String: func current_node_name()->String:
return _currentNode.nodeName return _currentNode.nodeName
@ -86,7 +75,7 @@ func set_selected_option(id):
printerr('Unable to select option when dialogue not waiting for option') printerr('Unable to select option when dialogue not waiting for option')
return false return false
if id < 0 || id >= _state.currentOptions.size(): if id < 0 or id >= _state.currentOptions.size():
printerr('%d is not a valid option ' % id) printerr('%d is not a valid option ' % id)
return false return false
@ -99,17 +88,17 @@ func set_selected_option(id):
return true return true
func has_options()->bool:
return _state.currentOptions.size() > 0
func reset(): func reset():
_state = VmState.new() _state = VmState.new()
#continue execution func get_next_instruction():
func resume()->bool: return null if _currentNode.instructions.size() - 1 <= _state.programCounter else _currentNode.instructions[_state.programCounter + 1]
func resume():
if _currentNode == null: if _currentNode == null:
printerr('Cannot run dialogue with no node selected') printerr('Cannot run dialogue with no node selected')
return false return false
if executionState == Constants.ExecutionState.WaitingForOption: if executionState == Constants.ExecutionState.WaitingForOption:
printerr('Cannot run while waiting for option') printerr('Cannot run while waiting for option')
return false return false
@ -132,7 +121,6 @@ func resume()->bool:
printerr('Cannot run without an nodeCompleteHandler') printerr('Cannot run without an nodeCompleteHandler')
return false return false
executionState = Constants.ExecutionState.Running executionState = Constants.ExecutionState.Running
#execute instruction until something cool happens #execute instruction until something cool happens
@ -147,7 +135,6 @@ func resume()->bool:
executionState = Constants.ExecutionState.Stopped executionState = Constants.ExecutionState.Stopped
reset() reset()
dialogueCompleteHandler.call_func() dialogueCompleteHandler.call_func()
_dialogue.dlog('Run Complete')
return true return true
@ -171,7 +158,7 @@ func run_instruction(instruction)->bool:
#pass it to client as line #pass it to client as line
var key = instruction.operands[0].value var key = instruction.operands[0].value
var line = Line.new(key) var line = _program.strings[key]
#the second operand is the expression count #the second operand is the expression count
# of format function # of format function
@ -180,7 +167,6 @@ func run_instruction(instruction)->bool:
var pause : int = lineHandler.call_func(line) var pause : int = lineHandler.call_func(line)
if pause == Constants.HandlerState.PauseExecution: if pause == Constants.HandlerState.PauseExecution:
executionState = Constants.ExecutionState.Suspended executionState = Constants.ExecutionState.Suspended
@ -190,7 +176,7 @@ func run_instruction(instruction)->bool:
if instruction.operands.size() > 1: if instruction.operands.size() > 1:
pass#add format function pass#add format function
var command = Command.new(commandText) var command = Program.Command.new(commandText)
var pause = commandHandler.call_func(command) as int var pause = commandHandler.call_func(command) as int
if pause == Constants.HandlerState.PauseExecution: if pause == Constants.HandlerState.PauseExecution:
@ -275,7 +261,7 @@ func run_instruction(instruction)->bool:
Constants.ByteCode.Stop: Constants.ByteCode.Stop:
#stop execution and repost it #stop execution and repost it
nodeCompleteHandler.call_func(_currentNode.nodeName) nodeCompleteHandler.call_func(_currentNode.name)
dialogueCompleteHandler.call_func() dialogueCompleteHandler.call_func()
executionState = Constants.ExecutionState.Stopped executionState = Constants.ExecutionState.Stopped
reset() reset()
@ -290,7 +276,7 @@ func run_instruction(instruction)->bool:
else : else :
name = instruction.operands[0].value name = instruction.operands[0].value
var pause = nodeCompleteHandler.call_func(_currentNode.nodeName) var pause = nodeCompleteHandler.call_func(_currentNode.name)
set_node(name) set_node(name)
_state.programCounter-=1 _state.programCounter-=1
if pause == Constants.HandlerState.PauseExecution: if pause == Constants.HandlerState.PauseExecution:
@ -300,7 +286,7 @@ func run_instruction(instruction)->bool:
# add an option to current state # add an option to current state
var key = instruction.operands[0].value var key = instruction.operands[0].value
var line = Line.new(key) var line = _program.strings[key]
if instruction.operands.size() > 2: if instruction.operands.size() > 2:
pass #formated text options pass #formated text options
@ -320,7 +306,7 @@ func run_instruction(instruction)->bool:
var choices : Array = []#Option var choices : Array = []#Option
for optionIndex in range(_state.currentOptions.size()): for optionIndex in range(_state.currentOptions.size()):
var option : SimpleEntry = _state.currentOptions[optionIndex] var option : SimpleEntry = _state.currentOptions[optionIndex]
choices.append(Option.new(option.key, optionIndex, option.value)) choices.append(Program.Option.new(option.key, optionIndex, option.value))
#we cant continue until option chosen #we cant continue until option chosen
executionState = Constants.ExecutionState.WaitingForOption executionState = Constants.ExecutionState.WaitingForOption
@ -353,7 +339,6 @@ class VmState:
else: else:
stack.push_back(Value.new(value)) stack.push_back(Value.new(value))
func pop_value(): func pop_value():
return stack.pop_back() return stack.pop_back()
@ -365,8 +350,8 @@ class VmState:
class SimpleEntry: class SimpleEntry:
var key var key
var value : String var value
func _init(key,value:String): func _init(key, value):
self.key = key self.key = key
self.value = value self.value = value

View file

@ -1,78 +1,41 @@
title: Start title: Start
tags: tags:
colorID: 0 colorID: 0
position: -1892,-1013 position: 0, 0
--- ---
<<load_situation The Revolver>> <<a_custom_command>>
<<animation elevator door open>> <<command_with multiple arguments>>
Masami: Gina, this way! #line:5d7a7c // remove "to" to trigger error
Gina: Patience! Im coming. <<set $direction to 'this'>>
>Still, she didnt pick up her pace and kept hesitantly looking around.< <<set $one to 1>>
Masami: Everything should be fine, lets just go. We won.
Masami: Unless you are planning on backstabbing me at the finish line, that is.
Gina: How funny. You are not that special.
Masami: Har har. Now start walking or Ill carry you out the front door.
Masami: I dont want to give Monokuma the time to come up with a new death game for two while we are trying to get through the exit.
Gina: ...
<<zoom to vault door>> // Implement inline expressions
Bob: Theresa, {$direction} way! #line:5d7a7c
Theresa: Did you know one + one equals {$one + $one}?
Bob: You wanna go somewhere?
Masami: Wait, the vault door… Its not open. [[Go to the store|TheStore]]
Gina: So it seems. [[Lets stay here and talk|Talk]]
Masami: But that doesnt make sense! So far we have opened one lock per two deceased. All seven locks should be open by now.
>In desperation I tried the vault handle. I wasnt exceptionally strong, but I doubted even a weightlifter could open this door whether it was held shut by one or dozen locks.<
Gina: Rather than using your energy by tearing at the 700kg door-
Masami: I wasnt trying to brute force it.
Gina: Anyway, I would suggest you spare a glance at the reception desk. It appears the staff has given us one last gift.
Masami: The reception desk?
<<zoom to gun>>
Masami: A paper and...
Masami: ... Thats a gun.
Gina: A revolver, in fact. Such an old fashioned choice of firearm. Though, I appreciate the aesthetic. How pretty.
Masami: I dont like this. Why is it here?
>I took the paper from the table and briskly unfolded it.<
- Congratulations on reaching the final part of the game!-
- Unfortunately, no one remembers a silver medalist.-
- Lets round up the game with a match of our favorite luck game! Russian roulette should be simple enough.-
- Now then, ladies first!-
-Staff-
Masami: Russian roulette… Are you kidding me?
Masami: This cant be part of the game. This wasnt in the rules!
Masami: I know the winning condition hasnt been met but-
Gina: Its rigged.
Masami: What?
>Gina had picked up the revolver from the table and without better judgement, opened the cylinder for inspection.<
Gina: Its rigged.
Masami: ... “Ladies first.”
Masami: The cylinder is full, isn't it?
>Gina let out a tired sigh. Her shoulders slumping heavily from disappointment.<
Gina: I got so far.
Gina: I dont know what led me to believe the outcome would be any different.
Gina: This is such a waste of resources as well.
Masami: Gina, put the revolver down. If the game is rigged, you dont have to play. The rules wont matter then.
Gina: Let it rest.
Gina: Like any of it matters.
Masami: What do you mean?
>She didnt answer.<
>Instead, she absentmindedly fiddled with the cylinder before locking it in place.<
>Then she spun the cylinder for the hell of it before raising the revolvers barrel against her very own temple.<
>She looked resigned. Though I couldnt help but notice the slight glint of fear in her eyes.<
>None of us wanted to die.<
Masami: Gina, please.
Gina: Congratulations.
Masami: Gina!
<<sound revolver_bang>>
<<fade_out>>
[[Waking up]]
=== ===
title: Waking up title: TheStore
tags: tags:
colorID: 0 colorID: 0
position: -1527,-881 position: 0, 200
--- ---
You: *waking up noices* Clerk: Welcome to the store.
Clerk: Can I help you with anything?
[[Go home|Start]]
===
title: Talk
tags:
colorID: 0
position: 0, 400
---
Bob: So how are you really?
Theresa: I'm good!
Bob: Do you want to continue talking?
-> Yes
[[Start]]
-> No
=== ===

View file

@ -38,7 +38,7 @@ _global_script_class_icons={
[application] [application]
config/name="YarnSpinner" 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"