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
func _ready():
pass
$VBoxContainer/ButtonTemplate.hide()
func continue_dialogue():
if $Tween.is_active():
@ -12,7 +12,6 @@ func continue_dialogue():
$Wol.resume()
func _on_Wol_line(line):
print(var2str(line))
$RichTextLabel.text = line.text
$Tween.remove_all()
@ -27,9 +26,27 @@ func _on_Wol_line(line):
$Tween.start()
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):
if event is InputEventKey and event.scancode == KEY_ENTER and event.pressed:
print('Pressed enter!')
continue_dialogue()

View file

@ -50,5 +50,6 @@ text = "This is a dialogue option"
[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="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(bool) var auto_start = false
export(NodePath) var variable_storage_path
export var auto_show_options = true
onready var variable_storage = get_node(variable_storage_path)
var program
var dialogue
var running = false
func _ready():
if Engine.editor_hint:
@ -62,6 +62,7 @@ func init_dialogue():
dialogue.set_program(program)
func set_path(_path):
if not Engine.editor_hint:
var file = File.new()
file.open(_path, File.READ)
var source = file.get_as_text()
@ -70,9 +71,11 @@ func set_path(_path):
path = _path
func _handle_line(line):
var id = line.id
var string = program.strings[id]
call_deferred('emit_signal', 'line', string)
call_deferred('emit_signal', 'line', line)
if auto_show_options \
and dialogue.get_vm().get_next_instruction().operation == Constants.ByteCode.AddOption:
return Constants.HandlerState.ContinueExecution
else:
return Constants.HandlerState.PauseExecution
func _handle_command(command):
@ -84,16 +87,14 @@ func _handle_command(command):
return Constants.HandlerState.ContinueExecution
func _handle_options(options):
call_deferred('emit_signal' ,'options', options)
call_deferred('emit_signal', 'options', options)
return Constants.HandlerState.PauseExecution
func _handle_dialogue_complete():
emit_signal('finished')
running = false
func _handle_node_start(node):
emit_signal('node_started', node)
print('node started')
dialogue.resume()
if !dialogue._visitedNodeCount.has(node):
@ -101,28 +102,23 @@ func _handle_node_start(node):
else:
dialogue._visitedNodeCount[node] += 1
print(dialogue._visitedNodeCount)
func _handle_node_complete(node):
emit_signal('node_completed', node)
running = false
return Constants.HandlerState.ContinueExecution
func select_option(id):
dialogue.get_vm().set_selected_option(id)
resume()
func pause():
dialogue.call_deferred('pause')
func start(node = start_node):
if running:
return
init_dialogue()
emit_signal('started')
running = true
dialogue.set_node(node)
dialogue.start()
func 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')
if field == 'title':
assert(not ' ' in value, 'No space allowed in title "%s", correct to "%s"' % [value, value.replace(' ','')])
title = value
if(line_number >= source_lines.size() || source_lines[line_number] == '---'):
@ -83,7 +84,7 @@ static func compile_string(source: String, filename: String):
#past header
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])
line_number+=1
@ -91,10 +92,9 @@ static func compile_string(source: String, filename: String):
body = body_lines.join('\n')
var lexer = Lexer.new()
var tokens = lexer.tokenize(body, title, filename)
var tokens : Array = lexer.tokenize(body)
var parser = Parser.new(tokens)
var parser = Parser.new(tokens, title)
var parser_node = parser.parse_node()
parser_node.name = title
@ -150,7 +150,7 @@ func compile_node(program, parsed_node):
if dangling_options:
emit(Constants.ByteCode.ShowOptions, node_compiled)
emit(Constants.ByteCode.Run_node, node_compiled)
emit(Constants.ByteCode.RunNode, node_compiled)
else:
emit(Constants.ByteCode.Stop, node_compiled)
@ -269,11 +269,15 @@ func generate_shortcut_group(node,shortcut_group):
if option.condition != null :
endof_clause = register_label('conditional_%s'%option_count)
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_string_id : String = register_string(option.label,node.node_name,
label_line_id,option.line_number,[])
var label_line_id = '' #TODO: Add tag support
var label_string_id = register_string(
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)])
@ -293,7 +297,7 @@ func generate_shortcut_group(node,shortcut_group):
if option.node != null :
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
#end of option group
@ -323,10 +327,10 @@ func generate_if(node,if_statement):
if clause.expression!=null:
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)
emit(Constants.ByteCode.Jump_to,node,[Program.Operand.new(endif)])
emit(Constants.ByteCode.JumpTo,node,[Program.Operand.new(endif)])
if clause.expression!=null:
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)])
else :
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)])
@ -357,13 +361,13 @@ func generate_option(node,option):
func generate_assignment(node,assignment):
# print('generating assign')
#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
generate_expression(node,assignment.value)
else :
#this is combined op
#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
generate_expression(node,assignment.value)
@ -371,16 +375,16 @@ func generate_assignment(node,assignment):
#stack contains oldvalue and result
match assignment.operation:
Constants.TokenType.Add_assign:
Constants.TokenType.AddAssign:
emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.Add))])
Constants.TokenType.Minus_assign:
Constants.TokenType.MinusAssign:
emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.Minus))])
Constants.TokenType.Multiply_assign:
Constants.TokenType.MultiplyAssign:
emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.MultiplyAssign))])
Constants.TokenType.Divide_assign:
Constants.TokenType.DivideAssign:
emit(Constants.ByteCode.CallFunc,node,
[Program.Operand.new(Constants.token_type_name(Constants.TokenType.DivideAssign))])
_:
@ -388,7 +392,7 @@ func generate_assignment(node,assignment):
#stack contains destination value
#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
emit(Constants.ByteCode.Pop,node)
@ -399,9 +403,9 @@ func generate_expression(node,expression):
# print('generating expression')
#expression = value || func call
match expression.type:
Constants.Expression_type.Value:
Constants.ExpressionType.Value:
generate_value(node,expression.value)
Constants.Expression_type.Function_call:
Constants.ExpressionType.FunctionCall:
#eval all parameters
for param in expression.params:
generate_expression(node,param)
@ -422,8 +426,8 @@ func generate_value(node,value):
Constants.ValueType.Number:
emit(Constants.ByteCode.PushNumber,node,[Program.Operand.new(value.value.as_number())])
Constants.ValueType.Str:
var id : String = register_string(value.value.as_string(),
node.node_name,'',value.line_number,[])
var id = register_string(value.value.as_string(),
node.name,'',value.line_number,[])
emit(Constants.ByteCode.PushString,node,[Program.Operand.new(id)])
Constants.ValueType.Boolean:
emit(Constants.ByteCode.PushBool,node,[Program.Operand.new(value.value.as_bool())])

View file

@ -35,50 +35,50 @@ func _init():
func create_states():
var patterns : Dictionary = {}
patterns[Constants.TokenType.Text] = '.*'
patterns[Constants.TokenType.Text] = ['.*', 'any text']
patterns[Constants.TokenType.Number] = '\\-?[0-9]+(\\.[0-9+])?'
patterns[Constants.TokenType.Str] = '\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\''
patterns[Constants.TokenType.TagMarker] = '\\#'
patterns[Constants.TokenType.LeftParen] = '\\('
patterns[Constants.TokenType.RightParen] = '\\)'
patterns[Constants.TokenType.EqualTo] = '(==|is(?!\\w)|eq(?!\\w))'
patterns[Constants.TokenType.EqualToOrAssign] = '(=|to(?!\\w))'
patterns[Constants.TokenType.NotEqualTo] = '(\\!=|neq(?!\\w))'
patterns[Constants.TokenType.GreaterThanOrEqualTo] = '(\\>=|gte(?!\\w))'
patterns[Constants.TokenType.GreaterThan] = '(\\>|gt(?!\\w))'
patterns[Constants.TokenType.LessThanOrEqualTo] = '(\\<=|lte(?!\\w))'
patterns[Constants.TokenType.LessThan] = '(\\<|lt(?!\\w))'
patterns[Constants.TokenType.AddAssign] = '\\+='
patterns[Constants.TokenType.MinusAssign] = '\\-='
patterns[Constants.TokenType.MultiplyAssign] = '\\*='
patterns[Constants.TokenType.DivideAssign] = '\\/='
patterns[Constants.TokenType.Add] = '\\+'
patterns[Constants.TokenType.Minus] = '\\-'
patterns[Constants.TokenType.Multiply] = '\\*'
patterns[Constants.TokenType.Divide] = '\\/'
patterns[Constants.TokenType.Modulo] = '\\%'
patterns[Constants.TokenType.And] = '(\\&\\&|and(?!\\w))'
patterns[Constants.TokenType.Or] = '(\\|\\||or(?!\\w))'
patterns[Constants.TokenType.Xor] = '(\\^|xor(?!\\w))'
patterns[Constants.TokenType.Not] = '(\\!|not(?!\\w))'
patterns[Constants.TokenType.Variable] = '\\$([A-Za-z0-9_\\.])+'
patterns[Constants.TokenType.Comma] = '\\,'
patterns[Constants.TokenType.TrueToken] = 'true(?!\\w)'
patterns[Constants.TokenType.FalseToken] = 'false(?!\\w)'
patterns[Constants.TokenType.NullToken] = 'null(?!\\w)'
patterns[Constants.TokenType.BeginCommand] = '\\<\\<'
patterns[Constants.TokenType.EndCommand] = '\\>\\>'
patterns[Constants.TokenType.OptionStart] = '\\[\\['
patterns[Constants.TokenType.OptionEnd] = '\\]\\]'
patterns[Constants.TokenType.OptionDelimit] = '\\|'
patterns[Constants.TokenType.Identifier] = '[a-zA-Z0-9_:\\.]+'
patterns[Constants.TokenType.IfToken] = 'if(?!\\w)'
patterns[Constants.TokenType.ElseToken] = 'else(?!\\w)'
patterns[Constants.TokenType.ElseIf] = 'elseif(?!\\w)'
patterns[Constants.TokenType.EndIf] = 'endif(?!\\w)'
patterns[Constants.TokenType.Set] = 'set(?!\\w)'
patterns[Constants.TokenType.ShortcutOption] = '\\-\\>\\s*'
patterns[Constants.TokenType.Number] = ['\\-?[0-9]+(\\.[0-9+])?', 'any number']
patterns[Constants.TokenType.Str] = ['\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\'', 'any text']
patterns[Constants.TokenType.TagMarker] = ['\\#', 'a tag #']
patterns[Constants.TokenType.LeftParen] = ['\\(', 'left parenthesis (']
patterns[Constants.TokenType.RightParen] = ['\\)', 'right parenthesis )']
patterns[Constants.TokenType.EqualTo] = ['(==|is(?!\\w)|eq(?!\\w))', '"=", "is" or "eq"']
patterns[Constants.TokenType.EqualToOrAssign] = ['(=|to(?!\\w))', 'equal to "=" or assign "="']
patterns[Constants.TokenType.NotEqualTo] = ['(\\!=|neq(?!\\w))', '"!=" or "neq"']
patterns[Constants.TokenType.GreaterThanOrEqualTo] = ['(\\>=|gte(?!\\w))', '">=" or "gte"']
patterns[Constants.TokenType.GreaterThan] = ['(\\>|gt(?!\\w))', '">" or "gt"']
patterns[Constants.TokenType.LessThanOrEqualTo] = ['(\\<=|lte(?!\\w))', '"<=" or "lte"']
patterns[Constants.TokenType.LessThan] = ['(\\<|lt(?!\\w))', '"<" or "lt"']
patterns[Constants.TokenType.AddAssign] = ['\\+=', '"+="']
patterns[Constants.TokenType.MinusAssign] = ['\\-=', '"-="']
patterns[Constants.TokenType.MultiplyAssign] = ['\\*=', '"*="']
patterns[Constants.TokenType.DivideAssign] = ['\\/=', '"/="']
patterns[Constants.TokenType.Add] = ['\\+', '"+"']
patterns[Constants.TokenType.Minus] = ['\\-', '"-"']
patterns[Constants.TokenType.Multiply] = ['\\*', '"*"']
patterns[Constants.TokenType.Divide] = ['\\/', '"/"']
patterns[Constants.TokenType.Modulo] = ['\\%', '"%"']
patterns[Constants.TokenType.And] = ['(\\&\\&|and(?!\\w))', '"&&" or "and"']
patterns[Constants.TokenType.Or] = ['(\\|\\||or(?!\\w))', '"||" or "or"']
patterns[Constants.TokenType.Xor] = ['(\\^|xor(?!\\w))', '"^" or "xor"']
patterns[Constants.TokenType.Not] = ['(\\!|not(?!\\w))', '"!" or "not"']
patterns[Constants.TokenType.Variable] = ['\\$([A-Za-z0-9_\\.])+', 'any variable']
patterns[Constants.TokenType.Comma] = ['\\,', '","']
patterns[Constants.TokenType.TrueToken] = ['true(?!\\w)', '"true"']
patterns[Constants.TokenType.FalseToken] = ['false(?!\\w)', '"false"']
patterns[Constants.TokenType.NullToken] = ['null(?!\\w)', '"null"']
patterns[Constants.TokenType.BeginCommand] = ['\\<\\<', 'beginning of a command "<<"']
patterns[Constants.TokenType.EndCommand] = ['\\>\\>', 'ending of a command ">>"']
patterns[Constants.TokenType.OptionStart] = ['\\[\\[', 'start of an option "[["']
patterns[Constants.TokenType.OptionEnd] = ['\\]\\]', 'end of an option "]]"']
patterns[Constants.TokenType.OptionDelimit] = ['\\|', 'middle of an option "|"']
patterns[Constants.TokenType.Identifier] = ['[a-zA-Z0-9_:\\.]+', 'any reference to another node']
patterns[Constants.TokenType.IfToken] = ['if(?!\\w)', '"if"']
patterns[Constants.TokenType.ElseToken] = ['else(?!\\w)', '"else"']
patterns[Constants.TokenType.ElseIf] = ['elseif(?!\\w)', '"elseif"']
patterns[Constants.TokenType.EndIf] = ['endif(?!\\w)', '"endif"']
patterns[Constants.TokenType.Set] = ['set(?!\\w)', '"set"']
patterns[Constants.TokenType.ShortcutOption] = ['\\-\\>\\s*', '"->"']
#compound states
var shortcut_option : String= SHORTCUT + DASH + OPTION
@ -173,10 +173,7 @@ func create_states():
for stateKey in _states.keys():
_states[stateKey].stateName = stateKey
pass
func tokenize(text:String)->Array:
func tokenize(text, title, filename):
_indentStack.clear()
_indentStack.push_front(IntBoolPair.new(0,false))
_shouldTrackIndent = false
@ -191,17 +188,20 @@ func tokenize(text:String)->Array:
var line_number : int = 1
for line in lines:
tokens+=tokenize_line(line,line_number)
line_number+=1
tokens += tokenize_line(line, line_number, title, filename)
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)
# print(tokens)
return tokens
func tokenize_line(line:String, line_number : int)->Array:
func tokenize_line(line, line_number, title, filename):
var tokenStack : Array = []
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
_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,'']
_shouldTrackIndent = false
@ -246,7 +252,7 @@ func tokenize_line(line:String, line_number : int)->Array:
var matched : bool = false
for rule in _currentState.rules:
var found : RegExMatch = rule.regex.search(freshLine, column)
var found = rule.regex.search(freshLine, column)
if !found:
continue
@ -273,9 +279,9 @@ func tokenize_line(line:String, line_number : int)->Array:
#
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:
tokenText = found.get_string()
@ -284,36 +290,51 @@ func tokenize_line(line:String, line_number : int)->Array:
#pre-proccess string
if rule.tokenType == Constants.TokenType.Str:
tokenText = tokenText.substr(1,tokenText.length() - 2)
tokenText = tokenText.substr(1, tokenText.length() - 2)
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
tokenStack.push_front(token)
if rule.enterState != null && rule.enterState.length() > 0:
if !_states.has(rule.enterState):
printerr('State[%s] not known - line(%s) col(%s)'%[rule.enterState,line_number,column])
if rule.enterState != null and rule.enterState.length() > 0:
if not _states.has(rule.enterState):
printerr('State[%s] not known - line(%s) col(%s)' % [rule.enterState, line_number, column])
return []
enter_state(_states[rule.enterState])
if _shouldTrackIndent:
if _indentStack.front().key < indentation:
_indentStack.append(IntBoolPair.new(indentation,false))
_indentStack.append(IntBoolPair.new(indentation, false))
matched = true
break
if !matched:
# TODO: Send out some helpful messages
printerr('expectedTokens [%s] - line(%s) col(%s)'%['refineErrors.Lexer.tokenize_line',line_number,column])
return []
if not matched:
var rules = []
for rule in _currentState.rules:
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:
column += lastWhiteSpace.get_string().length()
@ -339,20 +360,22 @@ func enter_state(state:LexerState):
_shouldTrackIndent = true
class Token:
var type : int
var value : String
var type = -1
var value = ''
var line_number : int
var column : int
var text : String
var filename = ''
var line_number = -1
var column = -1
var text = ''
var delimitsText : bool= false
var paramCount : int
var lexerState : String
var delimitsText = false
var paramCount = -1
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.lexerState = state.stateName
self.filename = filename
self.line_number = line_number
self.column = column
self.value = value
@ -360,7 +383,6 @@ class Token:
func _to_string():
return '%s (%s) at %s:%s (state: %s)' % [Constants.token_type_name(type),value,line_number,column,lexerState]
class LexerState:
var stateName : String
@ -372,9 +394,9 @@ class LexerState:
self.patterns = patterns
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)
var rule = Rule.new(type,pattern,state,delimitText)
var rule = Rule.new(type, pattern, patterns[type][1], state, delimitText)
rules.append(rule)
return rule
@ -409,16 +431,18 @@ class Rule:
var tokenType : int
var isTextRule : 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.regex = RegEx.new()
self.regex.compile(regex)
self.human_readable_identifier = human_readable_identifier
self.enterState = enterState
self.delimitsText = delimitsText
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:
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')
var _tokens = []
var title = ''
func _init(tokens):
func _init(tokens, title):
self._tokens = tokens
self.title = title
enum Associativity {
Left,
@ -37,7 +39,7 @@ func expect_symbol(token_types = []):
if token_types.size() == 0:
if token.type == Constants.TokenType.EndOfInput:
printerr('Unexpected end of input.')
assert(false, 'Unexpected end of input')
return null
return token
@ -45,8 +47,29 @@ func expect_symbol(token_types = []):
if token.type == type:
return token
printerr('Unexpexted token: expected[ %s ] but got [ %s ]' % token_types + [token.type])
return
var token_names = []
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):
return '%*s| %s%s' % [indent_level * 2, '', input, '' if not newline else '\n']
@ -55,12 +78,15 @@ func tokens():
return _tokens
class ParseNode:
var name = ''
var parent
var line_number = -1
var tags = []
func _init(parent, parser):
self.parent = parent
var tokens = parser.tokens() as Array
if tokens.size() > 0:
line_number = tokens.front().line_number
@ -77,7 +103,7 @@ class ParseNode:
func get_node_parent():
var node = self
while node != null:
if node.has_method('wol_node'):
if node is ParseNode:
return node as WolNode
node = node.parent
return null
@ -90,7 +116,6 @@ class ParseNode:
#this is a Wol Node - contains all the text
class WolNode extends ParseNode:
var name = ''
var source = ''
var editor_node_tags = []
@ -140,7 +165,7 @@ class Statement extends ParseNode:
elif Assignment.can_parse(parser):
assignment = Assignment.new(self, parser)
type = Type.Assignment_statement
type = Type.AssignmentStatement
elif ShortcutOptionGroup.can_parse(parser):
shortcut_option_group = ShortcutOptionGroup.new(self, parser)
@ -175,7 +200,7 @@ class Statement extends ParseNode:
info.append(block.tree_string(indent_level))
Type.IfStatement:
info.append(if_statement.tree_string(indent_level))
Type.Assignment_statement:
Type.AssignmentStatement:
info.append(assignment.tree_string(indent_level))
Type.OptionStatement:
info.append(option_statement.tree_string(indent_level))
@ -194,7 +219,7 @@ class CustomCommand extends ParseNode:
enum Type {
Expression,
Client_command
ClientCommand
}
var type = -1
@ -215,21 +240,21 @@ class CustomCommand extends ParseNode:
#if first token is identifier and second is leftt parenthesis
#evaluate as function
if (command_tokens.size() > 1 && command_tokens[0].type == Constants.TokenType.Identifier
&& command_tokens[1].type == Constants.TokenType.Left_paren):
&& command_tokens[1].type == Constants.TokenType.LeftParen):
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
self.expression = expression
else:
#otherwise evaluuate command
type = Type.Client_command
type = Type.ClientCommand
self.client_command = command_tokens[0].value
func tree_string(indent_level):
match type:
Type.Expression:
return tab(indent_level,'Expression: %s'% expression.tree_string(indent_level+1))
Type.Client_command:
Type.ClientCommand:
return tab(indent_level,'Command: %s' % client_command)
return ''
@ -246,10 +271,10 @@ class ShortcutOptionGroup extends ParseNode:
# expect one otherwise invalid
var index = 1
options.append(Short_cut_option.new(index, self, parser))
options.append(ShortCutOption.new(index, self, parser))
index += 1
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
func tree_string(indent_level):
@ -267,7 +292,7 @@ class ShortcutOptionGroup extends ParseNode:
static func can_parse(parser):
return parser.next_symbol_is([Constants.TokenType.ShortcutOption])
class Short_cut_option extends ParseNode:
class ShortCutOption extends ParseNode:
var label = ''
var condition
var node
@ -285,7 +310,7 @@ class Short_cut_option extends ParseNode:
if parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.IfToken]):
parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.IfToken])
condition = Expression_node.parse(self, parser)
condition = ExpressionNode.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand])
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]):
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])
@ -359,7 +384,6 @@ class OptionStatement extends ParseNode:
var label = ''
func _init(parent, parser).(parent, parser):
var strings = []
# NOTE: parse [[LABEL
@ -397,14 +421,14 @@ class IfStatement extends ParseNode:
parser.expect_symbol([Constants.TokenType.BeginCommand])
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])
#read statements until 'endif' or 'else' or 'else if'
var statements = []#statement
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.End_if]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_token]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_if]):
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.EndIf]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseToken]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseIf]):
statements.append(Statement.new(self, parser))
@ -416,20 +440,20 @@ class IfStatement extends ParseNode:
clauses.append(prime)
#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()
#parse condition syntax
parser.expect_symbol([Constants.TokenType.BeginCommand])
parser.expect_symbol([Constants.TokenType.Else_if])
clause_elif.expression = Expression_node.parse(self, parser)
parser.expect_symbol([Constants.TokenType.ElseIf])
clause_elif.expression = ExpressionNode.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand])
var elif_statements = []#statement
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.End_if]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_token]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.Else_if]):
while not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.EndIf]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseToken]) \
and not parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.ElseIf]):
elif_statements.append(Statement.new(self, parser))
@ -442,17 +466,17 @@ class IfStatement extends ParseNode:
#handle else if exists
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>>
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])
#parse until hit endif
var clause_else = Clause.new()
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))
clause_else.statements = el_statements
@ -464,7 +488,7 @@ class IfStatement extends ParseNode:
#finish
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])
@ -488,7 +512,7 @@ class IfStatement extends ParseNode:
return parser.next_symbols_are([Constants.TokenType.BeginCommand, Constants.TokenType.IfToken])
pass
class Value_node extends ParseNode:
class ValueNode extends ParseNode:
const Value = preload('res://addons/Wol/core/value.gd')
const Lexer = preload('res://addons/Wol/core/compiler/lexer.gd')
var value
@ -508,15 +532,15 @@ class Value_node extends ParseNode:
value = Value.new(float(token.value))
Constants.TokenType.Str:
value = Value.new(token.value)
Constants.TokenType.False_token:
Constants.TokenType.FalseToken:
value = Value.new(false)
Constants.TokenType.True_token:
Constants.TokenType.TrueToken:
value = Value.new(true)
Constants.TokenType.Variable:
value = Value.new(null)
value.type = Constants.Value_type.Variable
value.type = Constants.ValueType.Variable
value.variable = token.value
Constants.TokenType.Null_token:
Constants.TokenType.NullToken:
value = Value.new(null)
_:
printerr('%s, Invalid token type' % token.name)
@ -529,33 +553,32 @@ class Value_node extends ParseNode:
# math (1 + 2 - 5 * 3 / 10 % 2)
# Identifiers
# Values
class Expression_node extends ParseNode:
class ExpressionNode extends ParseNode:
var type
var value
var function
var params = []#Expression_node
var params = []#ExpressionNode
func _init(parent, parser, value, function = '', params = []).(parent, parser):
#no function - means value
if value != null:
self.type = Constants.Expression_type.Value
self.type = Constants.ExpressionType.Value
self.value = value
else:#function
self.type = Constants.Expression_type.Function_call
self.type = Constants.ExpressionType.FunctionCall
self.function = function
self.params = params
func tree_string(indent_level):
var info = []
match type:
Constants.Expression_type.Value:
Constants.ExpressionType.Value:
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()]))
for param in params:
#print('----> %s param_size:%s'%[(function) , params.size()])
info.append(param.tree_string(indent_level+1))
info.append(tab(indent_level,'}'))
@ -575,13 +598,13 @@ class Expression_node extends ParseNode:
Constants.TokenType.Number,
Constants.TokenType.Variable,
Constants.TokenType.Str,
Constants.TokenType.Left_paren,
Constants.TokenType.Right_paren,
Constants.TokenType.LeftParen,
Constants.TokenType.RightParen,
Constants.TokenType.Identifier,
Constants.TokenType.Comma,
Constants.TokenType.True_token,
Constants.TokenType.False_token,
Constants.TokenType.Null_token
Constants.TokenType.TrueToken,
Constants.TokenType.FalseToken,
Constants.TokenType.NullToken
]
valid_types += Operator.op_types()
valid_types.invert()
@ -595,9 +618,9 @@ class Expression_node extends ParseNode:
if next.type == Constants.TokenType.Variable \
or next.type == Constants.TokenType.Number \
or next.type == Constants.TokenType.Str \
or next.type == Constants.TokenType.False_token \
or next.type == Constants.TokenType.True_token \
or next.type == Constants.TokenType.Null_token:
or next.type == Constants.TokenType.FalseToken \
or next.type == Constants.TokenType.TrueToken \
or next.type == Constants.TokenType.NullToken:
#output primitives
rpn.append(next)
@ -606,12 +629,12 @@ class Expression_node extends ParseNode:
func_stack.push_back(next)
#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)
elif next.type == Constants.TokenType.Comma:
#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()
if p == null:
printerr('unbalanced parenthesis %s ' % next.name)
@ -621,7 +644,7 @@ class Expression_node extends ParseNode:
#next token in op_stack left paren
# next parser token not allowed to be right paren or comma
if parser.next_symbol_is([Constants.TokenType.Right_paren,
if parser.next_symbol_is([Constants.TokenType.RightParen,
Constants.TokenType.Comma]):
printerr('Expected Expression : %s' % parser.tokens().front().name)
@ -643,34 +666,33 @@ class Expression_node extends ParseNode:
if next.type == Constants.TokenType.Minus:
if last == null \
or last.type == Constants.TokenType.Left_paren \
or last.type == Constants.TokenType.LeftParen \
or Operator.is_op(last.type):
#unary minus
next.type = Constants.TokenType.Unary_minus
next.type = Constants.TokenType.UnaryMinus
#cannot assign inside expression
# x = a is the same as x == a
if next.type == Constants.TokenType.EqualToOrAssign:
next.type = Constants.TokenType.EqualTo
#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()
rpn.append(op)
op_stack.push_back(next)
elif next.type == Constants.TokenType.Left_paren:
elif next.type == Constants.TokenType.LeftParen:
#entered parenthesis sub expression
op_stack.push_back(next)
elif next.type == Constants.TokenType.Right_paren:
elif next.type == Constants.TokenType.RightParen:
#leaving sub expression
# 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())
if op_stack.back() == null:
printerr('Unbalanced parenthasis #Right_paren. Parser.Expression_node')
printerr('Unbalanced parenthasis #RightParen. Parser.ExpressionNode')
op_stack.pop_back()
@ -679,7 +701,7 @@ class Expression_node extends ParseNode:
#last token == left paren this == no params
#else
#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
rpn.append(op_stack.pop_back())
@ -698,10 +720,9 @@ class Expression_node extends ParseNode:
#build expression tree
var first = rpn.front()
var eval_stack = []#Expression_node
var eval_stack = []#ExpressionNode
while rpn.size() > 0:
var next = rpn.pop_front()
if Operator.is_op(next.type):
#operation
@ -710,7 +731,7 @@ class Expression_node extends ParseNode:
if eval_stack.size() < info.arguments:
printerr('Error parsing : Not enough arguments for %s [ got %s expected - was %s]'%[Constants.token_type_name(next.type), eval_stack.size(), info.arguments])
var params = []#Expression_node
var params = []#ExpressionNode
for i in range(info.arguments):
params.append(eval_stack.pop_back())
@ -718,7 +739,7 @@ class Expression_node extends ParseNode:
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)
@ -727,19 +748,19 @@ class Expression_node extends ParseNode:
var function = next.value
var params = []#Expression_node
var params = []#ExpressionNode
for i in range(next.param_count):
params.append(eval_stack.pop_back())
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)
else: #raw value
var value = Value_node.new(parent, parser, next)
var expression = Expression_node.new(parent, parser, value)
var value = ValueNode.new(parent, parser, next)
var expression = ExpressionNode.new(parent, parser, value)
eval_stack.append(expression)
@ -796,7 +817,7 @@ class Assignment extends ParseNode:
parser.expect_symbol([Constants.TokenType.Set])
destination = parser.expect_symbol([Constants.TokenType.Variable]).value
operation = parser.expect_symbol(Assignment.valid_ops()).type
value = Expression_node.parse(self, parser)
value = ExpressionNode.parse(self, parser)
parser.expect_symbol([Constants.TokenType.EndCommand])
func tree_string(indent_level):
@ -817,10 +838,10 @@ class Assignment extends ParseNode:
static func valid_ops():
return [
Constants.TokenType.EqualToOrAssign,
Constants.TokenType.Add_assign,
Constants.TokenType.Minus_assign,
Constants.TokenType.Divide_assign,
Constants.TokenType.Multiply_assign
Constants.TokenType.AddAssign,
Constants.TokenType.MinusAssign,
Constants.TokenType.DivideAssign,
Constants.TokenType.MultiplyAssign
]
class Operator extends ParseNode:
@ -848,22 +869,22 @@ class Operator extends ParseNode:
var TokenType = Constants.TokenType
match op:
TokenType.Not, TokenType.Unary_minus:
return Operator_info.new(Associativity.Right, 30, 1)
TokenType.Not, TokenType.UnaryMinus:
return OperatorInfo.new(Associativity.Right, 30, 1)
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:
return Operator_info.new(Associativity.Left, 15, 2)
return OperatorInfo.new(Associativity.Left, 15, 2)
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:
return Operator_info.new(Associativity.Left, 5, 2)
return OperatorInfo.new(Associativity.Left, 5, 2)
TokenType.And:
return Operator_info.new(Associativity.Left, 4, 2)
return OperatorInfo.new(Associativity.Left, 4, 2)
TokenType.Or:
return Operator_info.new(Associativity.Left, 3, 2)
return OperatorInfo.new(Associativity.Left, 3, 2)
TokenType.Xor:
return Operator_info.new(Associativity.Left, 2, 2)
return OperatorInfo.new(Associativity.Left, 2, 2)
_:
printerr('Unknown operator: %s' % op.name)
return null
@ -874,7 +895,7 @@ class Operator extends ParseNode:
static func op_types():
return [
Constants.TokenType.Not,
Constants.TokenType.Unary_minus,
Constants.TokenType.UnaryMinus,
Constants.TokenType.Add,
Constants.TokenType.Minus,
@ -897,7 +918,7 @@ class Operator extends ParseNode:
]
class Operator_info:
class OperatorInfo:
var associativity
var precedence = -1
var arguments = -1

View file

@ -198,3 +198,9 @@ static func bytecode_name(bytecode):
'Stop',
'RunNode'
][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
const DEFAULT_START = 'Start'
const FMF_PLACEHOLDE = '<VALUE PLACEHOLDER>'
const Constants = preload('res://addons/Wol/core/constants.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 _debugLog
var _errLog
var _program
var library
var _vm : VirtualMachine
var _vm
var _visitedNodeCount : Dictionary = {}
var _visitedNodeCount = {}
var executionComplete : bool
var executionComplete
func _init(variableStorage):
_variableStorage = variableStorage
_vm = VirtualMachine.new(self)
library = WolLibrary.new()
_debugLog = funcref(self, 'dlog')
_errLog = funcref(self, 'elog')
executionComplete = false
# import the standard library
@ -41,13 +35,6 @@ func _init(variableStorage):
#add function to lib that gets the node visit count
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():
return get_exec_state() != Constants.ExecutionState.Stopped
@ -55,15 +42,19 @@ func is_active():
func get_exec_state():
return _vm.executionState
func set_selected_option(option:int):
func 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)
func start():
if _vm.executionState == Constants.ExecutionState.Stopped:
_vm.resume()
func resume():
if _vm.executionState == Constants.ExecutionState.Running:
print('BLOCKED')
if _vm.executionState == Constants.ExecutionState.Running \
or _vm.executionState == Constants.ExecutionState.Stopped:
return
_vm.resume()
@ -81,12 +72,10 @@ func current_node():
func get_node_id(name):
if _program.nodes.size() == 0:
_errLog.call_func('No nodes loaded')
return ''
if _program.nodes.has(name):
return 'id:'+name
else:
_errLog.call_func('No node named [%s] exists' % name)
return ''
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()):
if node is Value:
node = _program.wolStrings[node.value()].text
node = _program.strings[node.value()].text
var visitCount : int = 0
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():
register_function("Add",2,funcref(self,"add"),true)
register_function("Minus",2,funcref(self,"sub"),true)
register_function("UnaryMinus",1,funcref(self,"unary_minus"),true)
register_function("Divide",2,funcref(self,"div"),true)
register_function("Multiply",2,funcref(self,"mul"),true)
register_function("Modulo",2,funcref(self,"mod"),true)
register_function("EqualTo",2,funcref(self,"equal"),true)
register_function("NotEqualTo",2,funcref(self,"noteq"),true)
register_function("GreaterThan",2,funcref(self,"ge"),true)
register_function("GreaterThanOrEqualTo",2,funcref(self,"geq"),true)
register_function("LessThan",2,funcref(self,"le"),true)
register_function("LessThanOrEqualTo",2,funcref(self,"leq"),true)
register_function("And",2,funcref(self,"land"),true)
register_function("Or",2,funcref(self,"lor"),true)
register_function("Xor",2,funcref(self,"xor"),true)
register_function("Not",1,funcref(self,"lnot"),true)
register_function('Add', 2, funcref(self, 'add'), true)
register_function('Minus', 2, funcref(self, 'sub'), true)
register_function('UnaryMinus', 1, funcref(self, 'unary_minus'), true)
register_function('Divide', 2, funcref(self, 'div'), true)
register_function('Multiply', 2, funcref(self, 'mul'), true)
register_function('Modulo', 2, funcref(self, 'mod'), true)
register_function('EqualTo', 2, funcref(self, 'equal'), true)
register_function('NotEqualTo', 2, funcref(self, 'noteq'), true)
register_function('GreaterThan', 2, funcref(self, 'ge'), true)
register_function('GreaterThanOrEqualTo', 2, funcref(self, 'geq'), true)
register_function('LessThan', 2, funcref(self, 'le'), true)
register_function('LessThanOrEqualTo', 2, funcref(self, 'leq'), true)
register_function('And', 2, funcref(self, 'land'), true)
register_function('Or', 2, funcref(self, 'lor'), true)
register_function('Xor', 2, funcref(self, 'xor'), true)
register_function('Not', 1, funcref(self, 'lnot'), true)
func add(param1:Value,param2:Value):
func add(param1, param2):
return param1.add(param2)
func sub(param1:Value,param2:Value):
func sub(param1, param2):
return param1.sub(param2)
func unary_minus(param1:Value):
func unary_minus(param1):
return param1.negative()
func div(param1:Value,param2:Value):
func div(param1, param2):
return param1.div(param2)
func mul(param1:Value,param2:Value):
func mul(param1, param2):
return param1.mult(param2)
func mod(param1:Value,param2:Value):
func mod(param1, param2):
return param1.mod(param2)
func equal(param1:Value,param2:Value):
func equal(param1, param2):
return param1.equals(param2)
func noteq(param1:Value,param2:Value):
func noteq(param1, param2):
return !param1.equals(param2)
func ge(param1:Value,param2:Value):
func ge(param1, param2):
return param1.greater(param2)
func geq(param1:Value,param2:Value):
func geq(param1, param2):
return param1.geq(param2)
func le(param1:Value,param2:Value):
func le(param1, param2):
return param1.less(param2)
func leq(param1:Value,param2:Value):
func leq(param1, param2):
return param1.leq(param2)
func land(param1:Value,param2:Value):
return param1.as_bool() && param2.as_bool()
func land(param1, param2):
return param1.as_bool() and param2.as_bool()
func lor(param1:Value,param2:Value):
return param1.as_bool() || param2.as_bool()
func lor(param1, param2):
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()
func lnot(param1:Value):
return !param1.as_bool()
func lnot(param1):
return not param1.as_bool()

View file

@ -22,6 +22,22 @@ class Line:
self.implicit = implicit
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:
var name = ''
var instructions = []

View file

@ -1,15 +1,7 @@
extends Node
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 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'
@ -54,15 +46,12 @@ func set_node(name:String) -> bool:
printerr('No node named %s has been loaded' % name)
return false
_dialogue.dlog('Running node %s' % name)
_currentNode = _program.nodes[name]
reset()
_state.currentNodeName = name
nodeStartHandler.call_func(name)
return true
func current_node_name()->String:
return _currentNode.nodeName
@ -86,8 +75,8 @@ func set_selected_option(id):
printerr('Unable to select option when dialogue not waiting for option')
return false
if id < 0 || id >= _state.currentOptions.size():
printerr('%d is not a valid option '%id)
if id < 0 or id >= _state.currentOptions.size():
printerr('%d is not a valid option ' % id)
return false
var destination = _state.currentOptions[id].value
@ -99,40 +88,39 @@ func set_selected_option(id):
return true
func has_options()->bool:
return _state.currentOptions.size() > 0
func reset():
_state = VmState.new()
#continue execution
func resume()->bool:
if _currentNode == null :
func get_next_instruction():
return null if _currentNode.instructions.size() - 1 <= _state.programCounter else _currentNode.instructions[_state.programCounter + 1]
func resume():
if _currentNode == null:
printerr('Cannot run dialogue with no node selected')
return false
if executionState == Constants.ExecutionState.WaitingForOption:
printerr('Cannot run while waiting for option')
return false
if lineHandler == null :
if lineHandler == null:
printerr('Cannot run without a lineHandler')
return false
if optionsHandler == null :
if optionsHandler == null:
printerr('Cannot run without an optionsHandler')
return false
if commandHandler == null :
if commandHandler == null:
printerr('Cannot run without an commandHandler')
return false
if nodeStartHandler == null :
if nodeStartHandler == null:
printerr('Cannot run without a nodeStartHandler')
return false
if nodeCompleteHandler == null :
if nodeCompleteHandler == null:
printerr('Cannot run without an nodeCompleteHandler')
return false
executionState = Constants.ExecutionState.Running
#execute instruction until something cool happens
@ -140,14 +128,13 @@ func resume()->bool:
var currentInstruction = _currentNode.instructions[_state.programCounter]
run_instruction(currentInstruction)
_state.programCounter+=1
_state.programCounter += 1
if _state.programCounter >= _currentNode.instructions.size():
nodeCompleteHandler.call_func(_currentNode.nodeName)
executionState = Constants.ExecutionState.Stopped
reset()
dialogueCompleteHandler.call_func()
_dialogue.dlog('Run Complete')
return true
@ -171,7 +158,7 @@ func run_instruction(instruction)->bool:
#pass it to client as line
var key = instruction.operands[0].value
var line = Line.new(key)
var line = _program.strings[key]
#the second operand is the expression count
# of format function
@ -180,7 +167,6 @@ func run_instruction(instruction)->bool:
var pause : int = lineHandler.call_func(line)
if pause == Constants.HandlerState.PauseExecution:
executionState = Constants.ExecutionState.Suspended
@ -190,7 +176,7 @@ func run_instruction(instruction)->bool:
if instruction.operands.size() > 1:
pass#add format function
var command = Command.new(commandText)
var command = Program.Command.new(commandText)
var pause = commandHandler.call_func(command) as int
if pause == Constants.HandlerState.PauseExecution:
@ -275,7 +261,7 @@ func run_instruction(instruction)->bool:
Constants.ByteCode.Stop:
#stop execution and repost it
nodeCompleteHandler.call_func(_currentNode.nodeName)
nodeCompleteHandler.call_func(_currentNode.name)
dialogueCompleteHandler.call_func()
executionState = Constants.ExecutionState.Stopped
reset()
@ -290,7 +276,7 @@ func run_instruction(instruction)->bool:
else :
name = instruction.operands[0].value
var pause = nodeCompleteHandler.call_func(_currentNode.nodeName)
var pause = nodeCompleteHandler.call_func(_currentNode.name)
set_node(name)
_state.programCounter-=1
if pause == Constants.HandlerState.PauseExecution:
@ -300,13 +286,13 @@ func run_instruction(instruction)->bool:
# add an option to current state
var key = instruction.operands[0].value
var line = Line.new(key)
var line = _program.strings[key]
if instruction.operands.size() > 2:
pass #formated text options
# line to show and node name
_state.currentOptions.append(SimpleEntry.new(line,instruction.operands[1].value))
_state.currentOptions.append(SimpleEntry.new(line, instruction.operands[1].value))
Constants.ByteCode.ShowOptions:
#show options - stop if none
@ -320,7 +306,7 @@ func run_instruction(instruction)->bool:
var choices : Array = []#Option
for optionIndex in range(_state.currentOptions.size()):
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
executionState = Constants.ExecutionState.WaitingForOption
@ -334,7 +320,7 @@ func run_instruction(instruction)->bool:
#bytecode messed up woopsise
executionState = Constants.ExecutionState.Stopped
reset()
printerr('Unknown Bytecode %s '%instruction.operation)
printerr('Unknown Bytecode %s' % instruction.operation)
return false
return true
@ -353,7 +339,6 @@ class VmState:
else:
stack.push_back(Value.new(value))
func pop_value():
return stack.pop_back()
@ -365,8 +350,8 @@ class VmState:
class SimpleEntry:
var key
var value : String
var value
func _init(key,value:String):
func _init(key, value):
self.key = key
self.value = value

View file

@ -1,78 +1,41 @@
title: Start
tags:
colorID: 0
position: -1892,-1013
position: 0, 0
---
<<load_situation The Revolver>>
<<animation elevator door open>>
<<a_custom_command>>
<<command_with multiple arguments>>
Masami: Gina, this way! #line:5d7a7c
Gina: Patience! Im coming.
>Still, she didnt pick up her pace and kept hesitantly looking around.<
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: ...
// remove "to" to trigger error
<<set $direction to 'this'>>
<<set $one to 1>>
<<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.
Gina: So it seems.
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]]
[[Go to the store|TheStore]]
[[Lets stay here and talk|Talk]]
===
title: Waking up
title: TheStore
tags:
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]
config/name="YarnSpinner"
config/name="Wol"
run/main_scene="res://Dialogue.tscn"
config/icon="res://icon.png"