did a bunch things to finalize
This commit is contained in:
parent
bad1dcb372
commit
c4868130eb
|
@ -16,6 +16,8 @@ __meta__ = {
|
||||||
script = ExtResource( 2 )
|
script = ExtResource( 2 )
|
||||||
path = "res://dialogue.yarn"
|
path = "res://dialogue.yarn"
|
||||||
auto_start = true
|
auto_start = true
|
||||||
|
variable_storage = {
|
||||||
|
}
|
||||||
|
|
||||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
|
|
|
@ -17,15 +17,17 @@ signal started
|
||||||
signal finished
|
signal finished
|
||||||
|
|
||||||
export(String, FILE, '*.wol,*.yarn') var path setget set_path
|
export(String, FILE, '*.wol,*.yarn') var path setget set_path
|
||||||
export(String) var start_node = 'Start'
|
|
||||||
export(bool) var auto_start = false
|
export var starting_node = 'Start'
|
||||||
|
export var auto_start = false
|
||||||
export var auto_show_options = true
|
export var auto_show_options = true
|
||||||
|
export var auto_substitute = true
|
||||||
|
|
||||||
export(Dictionary) var variable_storage = {}
|
export(Dictionary) var variable_storage = {}
|
||||||
|
|
||||||
const Constants = preload('res://addons/Wol/core/Constants.gd')
|
const Constants = preload('res://addons/Wol/core/Constants.gd')
|
||||||
const WolCompiler = preload('res://addons/Wol/core/compiler/Compiler.gd')
|
const Compiler = preload('res://addons/Wol/core/compiler/Compiler.gd')
|
||||||
const WolLibrary = preload('res://addons/Wol/core/Library.gd')
|
const Library = preload('res://addons/Wol/core/Library.gd')
|
||||||
const VirtualMachine = preload('res://addons/Wol/core/VirtualMachine.gd')
|
const VirtualMachine = preload('res://addons/Wol/core/VirtualMachine.gd')
|
||||||
const StandardLibrary = preload('res://addons/Wol/core/StandardLibrary.gd')
|
const StandardLibrary = preload('res://addons/Wol/core/StandardLibrary.gd')
|
||||||
|
|
||||||
|
@ -35,10 +37,11 @@ func _ready():
|
||||||
if Engine.editor_hint:
|
if Engine.editor_hint:
|
||||||
return
|
return
|
||||||
|
|
||||||
var libraries = WolLibrary.new()
|
var libraries = Library.new()
|
||||||
libraries.import_library(StandardLibrary.new())
|
|
||||||
virtual_machine = VirtualMachine.new(self, libraries)
|
virtual_machine = VirtualMachine.new(self, libraries)
|
||||||
|
|
||||||
|
libraries.import_library(StandardLibrary.new())
|
||||||
|
|
||||||
set_path(path)
|
set_path(path)
|
||||||
|
|
||||||
if auto_start:
|
if auto_start:
|
||||||
|
@ -48,10 +51,16 @@ func set_path(_path):
|
||||||
path = _path
|
path = _path
|
||||||
|
|
||||||
if not Engine.editor_hint and virtual_machine:
|
if not Engine.editor_hint and virtual_machine:
|
||||||
var compiler = WolCompiler.new(path)
|
var compiler = Compiler.new(path)
|
||||||
virtual_machine.program = compiler.compile()
|
virtual_machine.program = compiler.compile()
|
||||||
|
|
||||||
func _on_line(line):
|
func _on_line(line):
|
||||||
|
if auto_substitute:
|
||||||
|
var index = 0
|
||||||
|
for substitute in line.substitutions:
|
||||||
|
line.text = line.text.replace('{%d}' % index, substitute)
|
||||||
|
index += 1
|
||||||
|
|
||||||
call_deferred('emit_signal', 'line', line)
|
call_deferred('emit_signal', 'line', line)
|
||||||
if auto_show_options \
|
if auto_show_options \
|
||||||
and virtual_machine.get_next_instruction().operation == Constants.ByteCode.AddOption:
|
and virtual_machine.get_next_instruction().operation == Constants.ByteCode.AddOption:
|
||||||
|
@ -88,7 +97,7 @@ func select_option(id):
|
||||||
func pause():
|
func pause():
|
||||||
virtual_machine.call_deferred('pause')
|
virtual_machine.call_deferred('pause')
|
||||||
|
|
||||||
func start(node = start_node):
|
func start(node = starting_node):
|
||||||
emit_signal('started')
|
emit_signal('started')
|
||||||
|
|
||||||
virtual_machine.set_node(node)
|
virtual_machine.set_node(node)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
extends Object
|
extends Object
|
||||||
var Value : GDScript = load("res://addons/Wol/core/Value.gd")
|
|
||||||
|
const Value = preload("res://addons/Wol/core/Value.gd")
|
||||||
|
|
||||||
var name = ''
|
var name = ''
|
||||||
# NOTE: -1 means variable arguments
|
# NOTE: -1 means variable arguments
|
||||||
|
@ -18,12 +19,18 @@ func invoke(parameters = []):
|
||||||
if parameters != null:
|
if parameters != null:
|
||||||
length = parameters.size()
|
length = parameters.size()
|
||||||
|
|
||||||
if check_param_count(length):
|
if check_parameter_count(length):
|
||||||
if returns_value:
|
if returns_value:
|
||||||
|
var return_value
|
||||||
if length > 0:
|
if length > 0:
|
||||||
return Value.new(function.call_funcv(parameters))
|
return_value = function.call_funcv(parameters)
|
||||||
else:
|
else:
|
||||||
return Value.new(function.call_func())
|
return_value = function.call_func()
|
||||||
|
|
||||||
|
if return_value is Value:
|
||||||
|
return return_value
|
||||||
|
else:
|
||||||
|
return Value.new(return_value)
|
||||||
else:
|
else:
|
||||||
if length > 0:
|
if length > 0:
|
||||||
function.call_funcv(parameters)
|
function.call_funcv(parameters)
|
||||||
|
@ -31,5 +38,5 @@ func invoke(parameters = []):
|
||||||
function.call_func()
|
function.call_func()
|
||||||
return null
|
return null
|
||||||
|
|
||||||
func check_param_count(_parameter_count):
|
func check_parameter_count(_parameter_count):
|
||||||
return parameter_count == _parameter_count or parameter_count == -1
|
return parameter_count == _parameter_count or parameter_count == -1
|
||||||
|
|
|
@ -72,25 +72,14 @@ func xor(param1, param2):
|
||||||
func lnot(param1):
|
func lnot(param1):
|
||||||
return not param1.as_bool()
|
return not param1.as_bool()
|
||||||
|
|
||||||
var visited_node_count = {}
|
func is_node_visited(node = virtual_machine.current_node.name):
|
||||||
|
|
||||||
func is_node_visited(node = virtual_machine.current_node_name()):
|
|
||||||
return node_visit_count(node) > 0
|
return node_visit_count(node) > 0
|
||||||
|
|
||||||
func node_visit_count(node = virtual_machine.current_node_name()):
|
func node_visit_count(node = virtual_machine.current_node.name):
|
||||||
if node is Value:
|
if node is Value:
|
||||||
node = virtual_machine.program.strings[node.value()].text
|
node = virtual_machine.program.strings[node.value()].text
|
||||||
|
|
||||||
var visit_count = 0
|
var variable_storage = virtual_machine.dialogue.variable_storage
|
||||||
if visited_node_count.has(node):
|
var visited_node_count = variable_storage[virtual_machine.program.filename]
|
||||||
visit_count = visited_node_count[node]
|
|
||||||
|
|
||||||
return visit_count
|
return visited_node_count[node] if visited_node_count.has(node) else 0
|
||||||
|
|
||||||
func get_visited_nodes():
|
|
||||||
return visited_node_count.keys()
|
|
||||||
|
|
||||||
func set_visited_nodes(visitedList):
|
|
||||||
visited_node_count.clear()
|
|
||||||
for string in visitedList:
|
|
||||||
visited_node_count[string] = 1
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
extends Node
|
extends Object
|
||||||
|
|
||||||
const Constants = preload('res://addons/Wol/core/Constants.gd')
|
const Constants = preload('res://addons/Wol/core/Constants.gd')
|
||||||
|
const Program = preload('res://addons/Wol/core/Program.gd')
|
||||||
const Value = preload('res://addons/Wol/core/Value.gd')
|
const Value = preload('res://addons/Wol/core/Value.gd')
|
||||||
|
|
||||||
# Function references to handlers
|
# Function references to handlers
|
||||||
|
@ -59,8 +60,17 @@ func set_node(name):
|
||||||
|
|
||||||
current_node = program.nodes[name]
|
current_node = program.nodes[name]
|
||||||
reset()
|
reset()
|
||||||
|
|
||||||
state.current_node_name = name
|
state.current_node_name = name
|
||||||
node_start_handler.call_func(name)
|
node_start_handler.call_func(name)
|
||||||
|
|
||||||
|
if not dialogue.variable_storage.has(program.filename):
|
||||||
|
dialogue.variable_storage[program.filename] = {}
|
||||||
|
|
||||||
|
if not dialogue.variable_storage[program.filename].has(name):
|
||||||
|
dialogue.variable_storage[program.filename][name] = 0
|
||||||
|
|
||||||
|
dialogue.variable_storage[program.filename][name] += 1
|
||||||
return true
|
return true
|
||||||
|
|
||||||
func pause():
|
func pause():
|
||||||
|
@ -91,8 +101,8 @@ func reset():
|
||||||
state = VmState.new()
|
state = VmState.new()
|
||||||
|
|
||||||
func get_next_instruction():
|
func get_next_instruction():
|
||||||
if current_node.instructions.size() - 1 > state.programCounter:
|
if current_node.instructions.size() - 1 > state.program_counter:
|
||||||
return current_node.instructions[state.programCounter + 1]
|
return current_node.instructions[state.program_counter + 1]
|
||||||
return
|
return
|
||||||
|
|
||||||
func start():
|
func start():
|
||||||
|
@ -115,14 +125,13 @@ func resume():
|
||||||
|
|
||||||
execution_state = Constants.ExecutionState.Running
|
execution_state = Constants.ExecutionState.Running
|
||||||
|
|
||||||
#execute instruction until something cool happens
|
|
||||||
while execution_state == Constants.ExecutionState.Running:
|
while execution_state == Constants.ExecutionState.Running:
|
||||||
var current_instruction = current_node.instructions[state.programCounter]
|
var current_instruction = current_node.instructions[state.program_counter]
|
||||||
run_instruction(current_instruction)
|
run_instruction(current_instruction)
|
||||||
state.programCounter += 1
|
state.program_counter += 1
|
||||||
|
|
||||||
if state.programCounter >= current_node.instructions.size():
|
if state.program_counter >= current_node.instructions.size():
|
||||||
node_finished_handler.call_func(current_node.nodeName)
|
node_finished_handler.call_func(current_node.name)
|
||||||
execution_state = Constants.ExecutionState.Stopped
|
execution_state = Constants.ExecutionState.Stopped
|
||||||
reset()
|
reset()
|
||||||
dialogue_finished_handler.call_func()
|
dialogue_finished_handler.call_func()
|
||||||
|
@ -142,17 +151,22 @@ func run_instruction(instruction):
|
||||||
|
|
||||||
# Jump to named label
|
# Jump to named label
|
||||||
Constants.ByteCode.JumpTo:
|
Constants.ByteCode.JumpTo:
|
||||||
state.programCounter = find_label_instruction(instruction.operands[0].value) - 1
|
state.program_counter = find_label_instruction(instruction.operands[0].value) - 1
|
||||||
|
|
||||||
Constants.ByteCode.RunLine:
|
Constants.ByteCode.RunLine:
|
||||||
# Lookup string and give back as line
|
# Lookup string and give back as line
|
||||||
var key = instruction.operands[0].value
|
var key = instruction.operands[0].value
|
||||||
var line = program.strings[key]
|
var line = program.strings[key].clone()
|
||||||
|
|
||||||
# The second operand is the expression count of format function
|
# The second operand is the expression count of format function
|
||||||
# TODO: Add format functions supportk
|
# TODO: Add format functions support
|
||||||
|
line.substitutions = []
|
||||||
if instruction.operands.size() > 1:
|
if instruction.operands.size() > 1:
|
||||||
pass
|
var expression_count = int(instruction.operands[1].value)
|
||||||
|
|
||||||
|
while expression_count > 0:
|
||||||
|
line.substitutions.append(state.pop_value().as_string())
|
||||||
|
expression_count -= 1
|
||||||
|
|
||||||
var return_state = line_handler.call_func(line)
|
var return_state = line_handler.call_func(line)
|
||||||
|
|
||||||
|
@ -177,12 +191,12 @@ func run_instruction(instruction):
|
||||||
# Jump to named label if value of stack top is false
|
# Jump to named label if value of stack top is false
|
||||||
Constants.ByteCode.JumpIfFalse:
|
Constants.ByteCode.JumpIfFalse:
|
||||||
if not state.peek_value().as_bool():
|
if not state.peek_value().as_bool():
|
||||||
state.programCounter = find_label_instruction(instruction.operands[0].value) - 1
|
state.program_counter = find_label_instruction(instruction.operands[0].value) - 1
|
||||||
|
|
||||||
# Jump to label whose name is on the stack
|
# Jump to label whose name is on the stack
|
||||||
Constants.ByteCode.Jump:
|
Constants.ByteCode.Jump:
|
||||||
var destination = state.peek_value().as_string()
|
var destination = state.peek_value().as_string()
|
||||||
state.programCounter = find_label_instruction(destination) - 1
|
state.program_counter = find_label_instruction(destination) - 1
|
||||||
|
|
||||||
Constants.ByteCode.Pop:
|
Constants.ByteCode.Pop:
|
||||||
state.pop_value()
|
state.pop_value()
|
||||||
|
@ -204,25 +218,29 @@ func run_instruction(instruction):
|
||||||
if actual_parameter_count == 0:
|
if actual_parameter_count == 0:
|
||||||
result = function.invoke()
|
result = function.invoke()
|
||||||
else:
|
else:
|
||||||
var params = []
|
var parameters = []
|
||||||
for _i in range(actual_parameter_count):
|
for _i in range(actual_parameter_count):
|
||||||
params.push_front(state.pop_value())
|
parameters.push_front(state.pop_value())
|
||||||
|
|
||||||
result = function.invoke(params)
|
result = function.invoke(parameters)
|
||||||
|
|
||||||
if function.returns_value:
|
if function.returns_value:
|
||||||
state.push_value(result)
|
state.push_value(result)
|
||||||
|
|
||||||
Constants.ByteCode.PushVariable:
|
Constants.ByteCode.PushVariable:
|
||||||
var name = instruction.operands[0].value
|
var name = instruction.operands[0].value
|
||||||
var godot_value = dialogue.variable_storage[name]
|
var value = dialogue.variable_storage[name.replace('$', '')]
|
||||||
var value = Value.new(godot_value)
|
|
||||||
state.push_value(value)
|
state.push_value(value)
|
||||||
|
|
||||||
Constants.ByteCode.StoreVariable:
|
Constants.ByteCode.StoreVariable:
|
||||||
var value = state.peek_value()
|
var value = state.peek_value()
|
||||||
|
if value.type == Constants.ValueType.Str:
|
||||||
|
value = program.strings[value.value()].text
|
||||||
|
else:
|
||||||
|
value = value.value()
|
||||||
|
|
||||||
var name = instruction.operands[0].value.replace('$', '')
|
var name = instruction.operands[0].value.replace('$', '')
|
||||||
dialogue.variable_storage[name] = value.value()
|
dialogue.variable_storage[name] = value
|
||||||
|
|
||||||
Constants.ByteCode.Stop:
|
Constants.ByteCode.Stop:
|
||||||
node_finished_handler.call_func(current_node.name)
|
node_finished_handler.call_func(current_node.name)
|
||||||
|
@ -239,15 +257,15 @@ func run_instruction(instruction):
|
||||||
|
|
||||||
var return_state = node_finished_handler.call_func(current_node.name)
|
var return_state = node_finished_handler.call_func(current_node.name)
|
||||||
set_node(name)
|
set_node(name)
|
||||||
state.programCounter -= 1
|
|
||||||
if return_state == Constants.HandlerState.PauseExecution:
|
if return_state == Constants.HandlerState.PauseExecution:
|
||||||
execution_state = Constants.ExecutionState.Suspended
|
execution_state = Constants.ExecutionState.Suspended
|
||||||
|
|
||||||
Constants.ByteCode.AddOption:
|
Constants.ByteCode.AddOption:
|
||||||
var key = instruction.operands[0].value
|
var key = instruction.operands[0].value
|
||||||
var line = program.strings[key]
|
var line = program.strings[key].clone()
|
||||||
|
|
||||||
# TODO: Add format functions supportk
|
# TODO: Add format functions support
|
||||||
if instruction.operands.size() > 2:
|
if instruction.operands.size() > 2:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -280,11 +298,11 @@ func run_instruction(instruction):
|
||||||
|
|
||||||
class VmState:
|
class VmState:
|
||||||
var current_node_name = ''
|
var current_node_name = ''
|
||||||
var programCounter = 0
|
var program_counter = 0
|
||||||
var current_options = []
|
var current_options = []
|
||||||
var stack = []
|
var stack = []
|
||||||
|
|
||||||
func push_value(value)->void:
|
func push_value(value):
|
||||||
if value is Value:
|
if value is Value:
|
||||||
stack.push_back(value)
|
stack.push_back(value)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -79,7 +79,6 @@ func compile():
|
||||||
line_number += 1
|
line_number += 1
|
||||||
|
|
||||||
body = PoolStringArray(body_lines).join('\n')
|
body = PoolStringArray(body_lines).join('\n')
|
||||||
|
|
||||||
var lexer = Lexer.new(filename, title, body)
|
var lexer = Lexer.new(filename, title, body)
|
||||||
var tokens = lexer.tokenize()
|
var tokens = lexer.tokenize()
|
||||||
|
|
||||||
|
@ -94,6 +93,7 @@ func compile():
|
||||||
line_number += 1
|
line_number += 1
|
||||||
|
|
||||||
var program = Program.new()
|
var program = Program.new()
|
||||||
|
program.filename = filename
|
||||||
|
|
||||||
for node in parsed_nodes:
|
for node in parsed_nodes:
|
||||||
compile_node(program, node)
|
compile_node(program, node)
|
||||||
|
@ -203,7 +203,7 @@ func generate_statement(node, statement):
|
||||||
generate_assignment(node, statement.assignment)
|
generate_assignment(node, statement.assignment)
|
||||||
|
|
||||||
Constants.StatementTypes.Line:
|
Constants.StatementTypes.Line:
|
||||||
generate_line(node, statement,statement.line)
|
generate_line(node, statement)
|
||||||
_:
|
_:
|
||||||
assert(false, 'Illegal statement type [%s]. Could not generate code.' % statement.type)
|
assert(false, 'Illegal statement type [%s]. Could not generate code.' % statement.type)
|
||||||
|
|
||||||
|
@ -218,12 +218,19 @@ func generate_custom_command(node, command):
|
||||||
else :
|
else :
|
||||||
emit(Constants.ByteCode.RunCommand, node, [Program.Operand.new(command_string)])
|
emit(Constants.ByteCode.RunCommand, node, [Program.Operand.new(command_string)])
|
||||||
|
|
||||||
func generate_line(node, statement, line):
|
func generate_line(node, statement):
|
||||||
# TODO: Implement proper line numbers (global and local)
|
# TODO: Implement proper line numbers (global and local)
|
||||||
var num = register_string(line, node.name, '', statement.line_number, []);
|
var line = statement.line
|
||||||
emit(Constants.ByteCode.RunLine, node, [Program.Operand.new(num)])
|
var expression_count = line.substitutions.size()
|
||||||
|
|
||||||
func generate_shortcut_group(node,shortcut_group):
|
while not line.substitutions.empty():
|
||||||
|
var inline_expression = line.substitutions.pop_back()
|
||||||
|
generate_expression(node, inline_expression.expression)
|
||||||
|
|
||||||
|
var num = register_string(line.line_text, node.name, line.line_id, statement.line_number, line.tags);
|
||||||
|
emit(Constants.ByteCode.RunLine, node,[Program.Operand.new(num), Program.Operand.new(expression_count)])
|
||||||
|
|
||||||
|
func generate_shortcut_group(node, shortcut_group):
|
||||||
var end = register_label('group_end')
|
var end = register_label('group_end')
|
||||||
var labels = []
|
var labels = []
|
||||||
var option_count = 0
|
var option_count = 0
|
||||||
|
@ -243,7 +250,8 @@ func generate_shortcut_group(node,shortcut_group):
|
||||||
var label_string_id = register_string(
|
var label_string_id = register_string(
|
||||||
option.label,
|
option.label,
|
||||||
node.name,
|
node.name,
|
||||||
label_line_id,option.line_number,
|
label_line_id,
|
||||||
|
option.line_number,
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -287,7 +295,7 @@ func generate_if(node, if_statement):
|
||||||
generate_expression(node, clause.expression)
|
generate_expression(node, clause.expression)
|
||||||
emit(Constants.ByteCode.JumpIfFalse, 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.JumpTo, node, [Program.Operand.new(endif)])
|
emit(Constants.ByteCode.JumpTo, node, [Program.Operand.new(endif)])
|
||||||
|
|
||||||
if clause.expression != null:
|
if clause.expression != null:
|
||||||
|
|
|
@ -17,6 +17,8 @@ const ASSIGNMENT = 'assignment'
|
||||||
const OPTION = 'option'
|
const OPTION = 'option'
|
||||||
const OR = 'or'
|
const OR = 'or'
|
||||||
const DESTINATION = 'destination'
|
const DESTINATION = 'destination'
|
||||||
|
const INLINE = 'inline'
|
||||||
|
const FORMAT_FUNCTION = 'format'
|
||||||
|
|
||||||
var WHITESPACE = '\\s*'
|
var WHITESPACE = '\\s*'
|
||||||
|
|
||||||
|
@ -84,27 +86,40 @@ func createstates():
|
||||||
patterns[Constants.TokenType.EndIf] = ['endif(?!\\w)', '"endif"']
|
patterns[Constants.TokenType.EndIf] = ['endif(?!\\w)', '"endif"']
|
||||||
patterns[Constants.TokenType.Set] = ['set(?!\\w)', '"set"']
|
patterns[Constants.TokenType.Set] = ['set(?!\\w)', '"set"']
|
||||||
patterns[Constants.TokenType.ShortcutOption] = ['\\-\\>\\s*', '"->"']
|
patterns[Constants.TokenType.ShortcutOption] = ['\\-\\>\\s*', '"->"']
|
||||||
|
patterns[Constants.TokenType.ExpressionFunctionStart] = ['\\{', '"{"']
|
||||||
|
patterns[Constants.TokenType.ExpressionFunctionEnd] = ['\\}', '"}"']
|
||||||
|
patterns[Constants.TokenType.FormatFunctionStart] = ['(?<!\\[)\\[(?!\\[)', '"["']
|
||||||
|
patterns[Constants.TokenType.FormatFunctionEnd] = ['\\]', '"]"']
|
||||||
|
|
||||||
var shortcut_option = SHORTCUT + DASH + OPTION
|
var shortcut_option = SHORTCUT + DASH + OPTION
|
||||||
var shortcut_option_tag = shortcut_option + DASH + TAG
|
var shortcut_option_tag = shortcut_option + DASH + TAG
|
||||||
var command_or_expression = COMMAND + DASH + OR + DASH + EXPRESSION
|
var command_or_expression = COMMAND + DASH + OR + DASH + EXPRESSION
|
||||||
var link_destination = LINK + DASH + DESTINATION
|
var link_destination = LINK + DASH + DESTINATION
|
||||||
|
var format_expression = FORMAT_FUNCTION + DASH + EXPRESSION
|
||||||
|
var inline_expression = INLINE + DASH + EXPRESSION
|
||||||
|
var link_inline_expression = LINK + DASH + INLINE + DASH + EXPRESSION
|
||||||
|
var link_format_expression = LINK + DASH + FORMAT_FUNCTION + DASH + EXPRESSION
|
||||||
|
|
||||||
states = {}
|
states = {}
|
||||||
|
|
||||||
states[BASE] = LexerState.new(patterns)
|
states[BASE] = LexerState.new(patterns)
|
||||||
states[BASE].add_transition(Constants.TokenType.BeginCommand, COMMAND, true)
|
states[BASE].add_transition(Constants.TokenType.BeginCommand, COMMAND, true)
|
||||||
|
states[BASE].add_transition(Constants.TokenType.ExpressionFunctionStart, inline_expression, true)
|
||||||
|
states[BASE].add_transition(Constants.TokenType.FormatFunctionStart, FORMAT_FUNCTION, true)
|
||||||
states[BASE].add_transition(Constants.TokenType.OptionStart, LINK, true)
|
states[BASE].add_transition(Constants.TokenType.OptionStart, LINK, true)
|
||||||
states[BASE].add_transition(Constants.TokenType.ShortcutOption, shortcut_option)
|
states[BASE].add_transition(Constants.TokenType.ShortcutOption, shortcut_option)
|
||||||
states[BASE].add_transition(Constants.TokenType.TagMarker, TAG, true)
|
states[BASE].add_transition(Constants.TokenType.TagMarker, TAG, true)
|
||||||
states[BASE].add_text_rule(Constants.TokenType.Text)
|
states[BASE].add_text_rule(Constants.TokenType.Text)
|
||||||
|
|
||||||
|
#TODO: FIXME - Tags are not being proccessed properly this way. We must look for the format #{identifier}:{value}
|
||||||
|
# Possible solution is to add more transitions
|
||||||
states[TAG] = LexerState.new(patterns)
|
states[TAG] = LexerState.new(patterns)
|
||||||
states[TAG].add_transition(Constants.TokenType.Identifier, BASE)
|
states[TAG].add_transition(Constants.TokenType.Identifier, BASE)
|
||||||
|
|
||||||
states[shortcut_option] = LexerState.new(patterns)
|
states[shortcut_option] = LexerState.new(patterns)
|
||||||
states[shortcut_option].track_indent = true
|
states[shortcut_option].track_indent = true
|
||||||
states[shortcut_option].add_transition(Constants.TokenType.BeginCommand, EXPRESSION, true)
|
states[shortcut_option].add_transition(Constants.TokenType.BeginCommand, EXPRESSION, true)
|
||||||
|
states[shortcut_option].add_transition(Constants.TokenType.ExpressionFunctionStart, inline_expression, true)
|
||||||
states[shortcut_option].add_transition(Constants.TokenType.TagMarker, shortcut_option_tag, true)
|
states[shortcut_option].add_transition(Constants.TokenType.TagMarker, shortcut_option_tag, true)
|
||||||
states[shortcut_option].add_text_rule(Constants.TokenType.Text, BASE)
|
states[shortcut_option].add_text_rule(Constants.TokenType.Text, BASE)
|
||||||
|
|
||||||
|
@ -134,40 +149,42 @@ func createstates():
|
||||||
states[ASSIGNMENT].add_transition(Constants.TokenType.MultiplyAssign, EXPRESSION)
|
states[ASSIGNMENT].add_transition(Constants.TokenType.MultiplyAssign, EXPRESSION)
|
||||||
states[ASSIGNMENT].add_transition(Constants.TokenType.DivideAssign, EXPRESSION)
|
states[ASSIGNMENT].add_transition(Constants.TokenType.DivideAssign, EXPRESSION)
|
||||||
|
|
||||||
|
states[FORMAT_FUNCTION] = LexerState.new(patterns)
|
||||||
|
states[FORMAT_FUNCTION].add_transition(Constants.TokenType.FormatFunctionEnd, BASE, true)
|
||||||
|
states[FORMAT_FUNCTION].add_transition(Constants.TokenType.ExpressionFunctionStart, format_expression, true)
|
||||||
|
states[FORMAT_FUNCTION].add_text_rule(Constants.TokenType.Text)
|
||||||
|
|
||||||
|
|
||||||
|
states[format_expression] = LexerState.new(patterns)
|
||||||
|
states[format_expression].add_transition(Constants.TokenType.ExpressionFunctionEnd, FORMAT_FUNCTION)
|
||||||
|
form_expression_state(states[format_expression])
|
||||||
|
|
||||||
|
states[inline_expression] = LexerState.new(patterns)
|
||||||
|
states[inline_expression].add_transition(Constants.TokenType.ExpressionFunctionEnd, BASE)
|
||||||
|
form_expression_state(states[inline_expression])
|
||||||
|
|
||||||
states[EXPRESSION] = LexerState.new(patterns)
|
states[EXPRESSION] = LexerState.new(patterns)
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.EndCommand, BASE)
|
states[EXPRESSION].add_transition(Constants.TokenType.EndCommand, BASE)
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Number)
|
# states[EXPRESSION].add_transition(Constants.TokenType.FormatFunctionEnd, BASE)
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Str)
|
form_expression_state(states[EXPRESSION])
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.LeftParen)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.RightParen)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.EqualTo)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.EqualToOrAssign)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.NotEqualTo)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.GreaterThanOrEqualTo)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.GreaterThan)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.LessThanOrEqualTo)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.LessThan)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Add)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Minus)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Multiply)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Divide)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Modulo)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.And)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Or)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Xor)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Not)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Variable)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Comma)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.TrueToken)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.FalseToken)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.NullToken)
|
|
||||||
states[EXPRESSION].add_transition(Constants.TokenType.Identifier)
|
|
||||||
|
|
||||||
states[LINK] = LexerState.new(patterns)
|
states[LINK] = LexerState.new(patterns)
|
||||||
states[LINK].add_transition(Constants.TokenType.OptionEnd, BASE, true)
|
states[LINK].add_transition(Constants.TokenType.OptionEnd, BASE, true)
|
||||||
|
states[LINK].add_transition(Constants.TokenType.ExpressionFunctionStart, link_inline_expression, true)
|
||||||
|
states[LINK].add_transition(Constants.TokenType.FormatFunctionStart, link_format_expression, true)
|
||||||
|
states[LINK].add_transition(Constants.TokenType.FormatFunctionEnd, LINK, true)
|
||||||
states[LINK].add_transition(Constants.TokenType.OptionDelimit, link_destination, true)
|
states[LINK].add_transition(Constants.TokenType.OptionDelimit, link_destination, true)
|
||||||
states[LINK].add_text_rule(Constants.TokenType.Text)
|
states[LINK].add_text_rule(Constants.TokenType.Text)
|
||||||
|
|
||||||
|
states[link_format_expression] = LexerState.new(patterns)
|
||||||
|
states[link_format_expression].add_transition(Constants.TokenType.FormatFunctionEnd, LINK, true)
|
||||||
|
states[link_format_expression].add_transition(Constants.TokenType.ExpressionFunctionStart, link_inline_expression, true)
|
||||||
|
states[link_format_expression].add_text_rule(Constants.TokenType.Text)
|
||||||
|
|
||||||
|
states[link_inline_expression] = LexerState.new(patterns)
|
||||||
|
states[link_inline_expression].add_transition(Constants.TokenType.ExpressionFunctionEnd, LINK)
|
||||||
|
form_expression_state(states[link_inline_expression])
|
||||||
|
|
||||||
states[link_destination] = LexerState.new(patterns)
|
states[link_destination] = LexerState.new(patterns)
|
||||||
states[link_destination].add_transition(Constants.TokenType.Identifier)
|
states[link_destination].add_transition(Constants.TokenType.Identifier)
|
||||||
states[link_destination].add_transition(Constants.TokenType.OptionEnd, BASE)
|
states[link_destination].add_transition(Constants.TokenType.OptionEnd, BASE)
|
||||||
|
@ -177,6 +194,34 @@ func createstates():
|
||||||
for key in states.keys():
|
for key in states.keys():
|
||||||
states[key].name = key
|
states[key].name = key
|
||||||
|
|
||||||
|
func form_expression_state(expression_state):
|
||||||
|
expression_state.add_transition(Constants.TokenType.Number)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Str)
|
||||||
|
expression_state.add_transition(Constants.TokenType.LeftParen)
|
||||||
|
expression_state.add_transition(Constants.TokenType.RightParen)
|
||||||
|
expression_state.add_transition(Constants.TokenType.EqualTo)
|
||||||
|
expression_state.add_transition(Constants.TokenType.EqualToOrAssign)
|
||||||
|
expression_state.add_transition(Constants.TokenType.NotEqualTo)
|
||||||
|
expression_state.add_transition(Constants.TokenType.GreaterThanOrEqualTo)
|
||||||
|
expression_state.add_transition(Constants.TokenType.GreaterThan)
|
||||||
|
expression_state.add_transition(Constants.TokenType.LessThanOrEqualTo)
|
||||||
|
expression_state.add_transition(Constants.TokenType.LessThan)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Add)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Minus)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Multiply)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Divide)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Modulo)
|
||||||
|
expression_state.add_transition(Constants.TokenType.And)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Or)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Xor)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Not)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Variable)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Comma)
|
||||||
|
expression_state.add_transition(Constants.TokenType.TrueToken)
|
||||||
|
expression_state.add_transition(Constants.TokenType.FalseToken)
|
||||||
|
expression_state.add_transition(Constants.TokenType.NullToken)
|
||||||
|
expression_state.add_transition(Constants.TokenType.Identifier)
|
||||||
|
|
||||||
func tokenize():
|
func tokenize():
|
||||||
var tokens = []
|
var tokens = []
|
||||||
|
|
||||||
|
@ -371,7 +416,7 @@ class Token:
|
||||||
value = _value
|
value = _value
|
||||||
|
|
||||||
func _to_string():
|
func _to_string():
|
||||||
return '%s (%s) at %s:%s (state: %s)' % [Constants.token_type_name(type),value, line_number, column, lexer_state]
|
return '%s (%s) at %s:%s (state: %s)' % [Constants.token_type_name(type), value, line_number, column, lexer_state]
|
||||||
|
|
||||||
class LexerState:
|
class LexerState:
|
||||||
var name = ''
|
var name = ''
|
||||||
|
|
|
@ -87,8 +87,6 @@ class ParseNode:
|
||||||
var tokens = _parser.tokens as Array
|
var tokens = _parser.tokens as Array
|
||||||
if tokens.size() > 0:
|
if tokens.size() > 0:
|
||||||
line_number = tokens.front().line_number
|
line_number = tokens.front().line_number
|
||||||
else:
|
|
||||||
line_number = -1
|
|
||||||
|
|
||||||
tags = []
|
tags = []
|
||||||
|
|
||||||
|
@ -132,6 +130,105 @@ class WolNode extends ParseNode:
|
||||||
class Header extends ParseNode:
|
class Header extends ParseNode:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class InlineExpression extends ParseNode:
|
||||||
|
var expression
|
||||||
|
|
||||||
|
func _init(parent, parser).(parent, parser):
|
||||||
|
parser.expect_symbol([Constants.TokenType.ExpressionFunctionStart])
|
||||||
|
expression = ExpressionNode.parse(self, parser)
|
||||||
|
parser.expect_symbol([Constants.TokenType.ExpressionFunctionEnd])
|
||||||
|
|
||||||
|
static func can_parse(parser):
|
||||||
|
return parser.next_symbol_is([Constants.TokenType.ExpressionFunctionStart])
|
||||||
|
|
||||||
|
func tree_string(_indent_level):
|
||||||
|
return "InlineExpression:"
|
||||||
|
|
||||||
|
# Returns a format_text string as [ name "{0}" key1="value1" key2="value2" ]
|
||||||
|
class FormatFunctionNode extends ParseNode:
|
||||||
|
var format_text = ''
|
||||||
|
var expression_value
|
||||||
|
|
||||||
|
func _init(parent:ParseNode, parser, expressionCount:int).(parent, parser):
|
||||||
|
format_text="["
|
||||||
|
parser.expect_symbol([Constants.TokenType.FormatFunctionStart])
|
||||||
|
|
||||||
|
while !parser.next_symbol_is([Constants.TokenType.FormatFunctionEnd]):
|
||||||
|
if parser.next_symbol_is([Constants.TokenType.Text]):
|
||||||
|
format_text += parser.expect_symbol().value
|
||||||
|
|
||||||
|
if InlineExpression.can_parse(parser):
|
||||||
|
expression_value = InlineExpression.new(self, parser)
|
||||||
|
format_text +=" \"{%d}\" " % expressionCount
|
||||||
|
parser.expect_symbol()
|
||||||
|
format_text+="]"
|
||||||
|
|
||||||
|
static func can_parse(parser):
|
||||||
|
return parser.next_symbol_is([Constants.TokenType.FormatFunctionStart])
|
||||||
|
|
||||||
|
# TODO: Make format prettier and add more information
|
||||||
|
func tree_string(_indent_level):
|
||||||
|
return "FormatFunction"
|
||||||
|
|
||||||
|
class LineNode extends ParseNode:
|
||||||
|
var line_text = ''
|
||||||
|
# FIXME: Right now we are putting the formatfunctions and inline expressions in the same
|
||||||
|
# list but if at some point we want to stronly type our sub list we need to make a new
|
||||||
|
# parse node that can have either an InlineExpression or a FunctionFormat
|
||||||
|
# .. This is a consideration for Godot4.x
|
||||||
|
var substitutions = []
|
||||||
|
var line_id = ''
|
||||||
|
var line_tags = []
|
||||||
|
|
||||||
|
# NOTE: If format function an inline functions are both present
|
||||||
|
# returns a line in the format "Some text {0} and some other {1}[format "{2}" key="value" key="value"]"
|
||||||
|
|
||||||
|
func _init(parent, parser).(parent, parser):
|
||||||
|
while parser.next_symbol_is(
|
||||||
|
[
|
||||||
|
Constants.TokenType.FormatFunctionStart,
|
||||||
|
Constants.TokenType.ExpressionFunctionStart,
|
||||||
|
Constants.TokenType.Text,
|
||||||
|
Constants.TokenType.TagMarker
|
||||||
|
]
|
||||||
|
):
|
||||||
|
|
||||||
|
if FormatFunctionNode.can_parse(parser):
|
||||||
|
var format_function = FormatFunctionNode.new(self, parser, substitutions.size())
|
||||||
|
if format_function.expression_value != null:
|
||||||
|
substitutions.append(format_function.expression_value)
|
||||||
|
|
||||||
|
line_text += format_function.format_text
|
||||||
|
|
||||||
|
elif InlineExpression.can_parse(parser):
|
||||||
|
var inline_expression = InlineExpression.new(self, parser)
|
||||||
|
line_text += '{%d}' % substitutions.size()
|
||||||
|
substitutions.append(inline_expression)
|
||||||
|
|
||||||
|
elif parser.next_symbols_are([Constants.TokenType.TagMarker, Constants.TokenType.Identifier]):
|
||||||
|
parser.expect_symbol()
|
||||||
|
var tag_token = parser.expect_symbol([ Constants.TokenType.Identifier ])
|
||||||
|
if tag_token.value.begins_with("line:"):
|
||||||
|
if line_id.empty():
|
||||||
|
line_id = tag_token.value
|
||||||
|
else:
|
||||||
|
printerr("Too many line_tags @[%s:%d]" %[parser.currentNodeName, tag_token.line_number])
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
tags.append(tag_token.value)
|
||||||
|
|
||||||
|
else:
|
||||||
|
var token = parser.expect_symbol()
|
||||||
|
if token.line_number == line_number and token.type != Constants.TokenType.BeginCommand:
|
||||||
|
line_text += token.value
|
||||||
|
else:
|
||||||
|
parser.tokens.push_front(token)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
func tree_string(indent_level):
|
||||||
|
return tab(indent_level, 'Line: (%s)[%d]' % [line_text, substitutions.size()])
|
||||||
|
|
||||||
class Statement extends ParseNode:
|
class Statement extends ParseNode:
|
||||||
var Type = Constants.StatementTypes
|
var Type = Constants.StatementTypes
|
||||||
|
|
||||||
|
@ -142,7 +239,7 @@ class Statement extends ParseNode:
|
||||||
var assignment
|
var assignment
|
||||||
var shortcut_option_group
|
var shortcut_option_group
|
||||||
var custom_command
|
var custom_command
|
||||||
var line = ''
|
var line
|
||||||
|
|
||||||
func _init(parent, parser).(parent, parser):
|
func _init(parent, parser).(parent, parser):
|
||||||
if Block.can_parse(parser):
|
if Block.can_parse(parser):
|
||||||
|
@ -170,7 +267,7 @@ class Statement extends ParseNode:
|
||||||
type = Type.CustomCommand
|
type = Type.CustomCommand
|
||||||
|
|
||||||
elif parser.next_symbol_is([Constants.TokenType.Text]):
|
elif parser.next_symbol_is([Constants.TokenType.Text]):
|
||||||
line = parser.expect_symbol([Constants.TokenType.Text]).value
|
line = LineNode.new(self, parser)
|
||||||
type = Type.Line
|
type = Type.Line
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -203,7 +300,7 @@ class Statement extends ParseNode:
|
||||||
Type.CustomCommand:
|
Type.CustomCommand:
|
||||||
info.append(custom_command.tree_string(indent_level))
|
info.append(custom_command.tree_string(indent_level))
|
||||||
Type.Line:
|
Type.Line:
|
||||||
info.append(tab(indent_level, 'Line: %s' % line))
|
info.append(line.tree_string(indent_level))
|
||||||
_:
|
_:
|
||||||
printerr('Cannot print statement')
|
printerr('Cannot print statement')
|
||||||
|
|
||||||
|
@ -233,11 +330,14 @@ 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[1].type == Constants.TokenType.LeftParen):
|
and command_tokens[0].type == Constants.TokenType.Identifier \
|
||||||
|
and 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)
|
||||||
expression = ExpressionNode.parse(self, p)
|
expression = ExpressionNode.parse(self, p)
|
||||||
type = Type.Expression
|
type = Type.Expression
|
||||||
|
|
||||||
else:
|
else:
|
||||||
#otherwise evaluuate command
|
#otherwise evaluuate command
|
||||||
type = Type.ClientCommand
|
type = Type.ClientCommand
|
||||||
|
@ -545,10 +645,10 @@ class ExpressionNode extends ParseNode:
|
||||||
var parameters = []
|
var parameters = []
|
||||||
|
|
||||||
func _init(parent, parser, _value, _function = '', _parameters = []).(parent, parser):
|
func _init(parent, parser, _value, _function = '', _parameters = []).(parent, parser):
|
||||||
|
|
||||||
if _value != null:
|
if _value != null:
|
||||||
type = Constants.ExpressionType.Value
|
type = Constants.ExpressionType.Value
|
||||||
value = _value
|
value = _value
|
||||||
|
|
||||||
else:
|
else:
|
||||||
type = Constants.ExpressionType.FunctionCall
|
type = Constants.ExpressionType.FunctionCall
|
||||||
function = _function
|
function = _function
|
||||||
|
@ -568,7 +668,7 @@ class ExpressionNode extends ParseNode:
|
||||||
|
|
||||||
return info.join('')
|
return info.join('')
|
||||||
|
|
||||||
# using Djikstra's shunting-yard algorithm to convert stream of expresions into postfix notation,
|
# Using Djikstra's shunting-yard algorithm to convert stream of expresions into postfix notation,
|
||||||
# & then build a tree of expressions
|
# & then build a tree of expressions
|
||||||
static func parse(parent, parser):
|
static func parse(parent, parser):
|
||||||
var rpn = []
|
var rpn = []
|
||||||
|
@ -595,7 +695,7 @@ class ExpressionNode extends ParseNode:
|
||||||
var last
|
var last
|
||||||
|
|
||||||
#read expression content
|
#read expression content
|
||||||
while parser.tokens.size() > 0 && parser.next_symbol_is(valid_types):
|
while parser.tokens.size() > 0 and parser.next_symbol_is(valid_types):
|
||||||
var next = parser.expect_symbol(valid_types)
|
var next = parser.expect_symbol(valid_types)
|
||||||
|
|
||||||
if next.type == Constants.TokenType.Variable \
|
if next.type == Constants.TokenType.Variable \
|
||||||
|
@ -633,7 +733,7 @@ class ExpressionNode extends ParseNode:
|
||||||
|
|
||||||
#find the closest function on stack
|
#find the closest function on stack
|
||||||
#increment parameters
|
#increment parameters
|
||||||
func_stack.back().param_count+=1
|
func_stack.back().parameter_count+=1
|
||||||
|
|
||||||
elif Operator.is_op(next.type):
|
elif Operator.is_op(next.type):
|
||||||
#this is an operator
|
#this is an operator
|
||||||
|
@ -685,7 +785,7 @@ class ExpressionNode extends ParseNode:
|
||||||
#else
|
#else
|
||||||
#we have more than 1 param
|
#we have more than 1 param
|
||||||
if last.type != Constants.TokenType.LeftParen:
|
if last.type != Constants.TokenType.LeftParen:
|
||||||
func_stack.back().param_count+=1
|
func_stack.back().parameter_count+=1
|
||||||
|
|
||||||
rpn.append(op_stack.pop_back())
|
rpn.append(op_stack.pop_back())
|
||||||
func_stack.pop_back()
|
func_stack.pop_back()
|
||||||
|
@ -730,7 +830,7 @@ class ExpressionNode extends ParseNode:
|
||||||
var function_name = next.value
|
var function_name = next.value
|
||||||
|
|
||||||
var function_parameters = []
|
var function_parameters = []
|
||||||
for _i in range(next.param_count):
|
for _i in range(next.parameter_count):
|
||||||
function_parameters.append(eval_stack.pop_back())
|
function_parameters.append(eval_stack.pop_back())
|
||||||
|
|
||||||
function_parameters.invert()
|
function_parameters.invert()
|
||||||
|
@ -802,7 +902,7 @@ class Assignment extends ParseNode:
|
||||||
info.append(tab(indent_level + 1, destination))
|
info.append(tab(indent_level + 1, destination))
|
||||||
info.append(tab(indent_level + 1, Constants.token_type_name(operation)))
|
info.append(tab(indent_level + 1, Constants.token_type_name(operation)))
|
||||||
info.append(value.tree_string(indent_level + 1))
|
info.append(value.tree_string(indent_level + 1))
|
||||||
return info.join('')
|
return PoolStringArray(info).join('')
|
||||||
|
|
||||||
|
|
||||||
static func can_parse(parser):
|
static func can_parse(parser):
|
||||||
|
|
|
@ -76,6 +76,12 @@ enum TokenType {
|
||||||
#8 Command syntax ('<<foo>>')
|
#8 Command syntax ('<<foo>>')
|
||||||
BeginCommand, EndCommand,
|
BeginCommand, EndCommand,
|
||||||
|
|
||||||
|
ExpressionFunctionStart, # {
|
||||||
|
ExpressionFunctionEnd, # }
|
||||||
|
|
||||||
|
FormatFunctionStart, # [
|
||||||
|
FormatFunctionEnd, # ]
|
||||||
|
|
||||||
#10 Variables ('$foo')
|
#10 Variables ('$foo')
|
||||||
Variable,
|
Variable,
|
||||||
|
|
||||||
|
@ -145,7 +151,8 @@ enum TokenType {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ExpressionType {
|
enum ExpressionType {
|
||||||
Value, FunctionCall
|
Value,
|
||||||
|
FunctionCall
|
||||||
}
|
}
|
||||||
|
|
||||||
enum StatementTypes {
|
enum StatementTypes {
|
||||||
|
@ -155,7 +162,8 @@ enum StatementTypes {
|
||||||
IfStatement,
|
IfStatement,
|
||||||
OptionStatement,
|
OptionStatement,
|
||||||
AssignmentStatement,
|
AssignmentStatement,
|
||||||
Line
|
Line,
|
||||||
|
InlineExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ValueType {
|
enum ValueType {
|
||||||
|
|
|
@ -15,6 +15,7 @@ func get_function(name):
|
||||||
|
|
||||||
func import_library(other):
|
func import_library(other):
|
||||||
Constants.merge_dir(functions, other.functions)
|
Constants.merge_dir(functions, other.functions)
|
||||||
|
other.virtual_machine = virtual_machine
|
||||||
|
|
||||||
func register_function(name, parameter_count, function, returns_value):
|
func register_function(name, parameter_count, function, returns_value):
|
||||||
var functionInfo = FunctionInfo.new(name, parameter_count, function, returns_value)
|
var functionInfo = FunctionInfo.new(name, parameter_count, function, returns_value)
|
||||||
|
|
|
@ -3,6 +3,7 @@ extends Object
|
||||||
const Constants = preload('res://addons/Wol/core/Constants.gd')
|
const Constants = preload('res://addons/Wol/core/Constants.gd')
|
||||||
|
|
||||||
var name = ''
|
var name = ''
|
||||||
|
var filename = ''
|
||||||
var strings = {}
|
var strings = {}
|
||||||
var nodes = {}
|
var nodes = {}
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@ class Line:
|
||||||
var line_number = -1
|
var line_number = -1
|
||||||
var file_name = ''
|
var file_name = ''
|
||||||
var implicit = false
|
var implicit = false
|
||||||
|
var substitutions = []
|
||||||
var meta = []
|
var meta = []
|
||||||
|
|
||||||
func _init(_text, _node_name, _line_number, _file_name, _implicit, _meta):
|
func _init(_text, _node_name, _line_number, _file_name, _implicit, _meta):
|
||||||
|
@ -21,6 +23,13 @@ class Line:
|
||||||
implicit = _implicit
|
implicit = _implicit
|
||||||
meta = _meta
|
meta = _meta
|
||||||
|
|
||||||
|
func clone():
|
||||||
|
return get_script().new(text, node_name, line_number, file_name, implicit, meta)
|
||||||
|
|
||||||
|
func _to_string():
|
||||||
|
return '%s:%d: "%s"' % [file_name.get_file(), line_number, text]
|
||||||
|
|
||||||
|
|
||||||
class Option:
|
class Option:
|
||||||
var line
|
var line
|
||||||
var id = -1
|
var id = -1
|
||||||
|
@ -31,6 +40,9 @@ class Option:
|
||||||
id = _id
|
id = _id
|
||||||
destination = _destination
|
destination = _destination
|
||||||
|
|
||||||
|
func clone():
|
||||||
|
return get_script().new(self)
|
||||||
|
|
||||||
class Command:
|
class Command:
|
||||||
var command = ''
|
var command = ''
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,6 @@ extends Object
|
||||||
|
|
||||||
const Constants = preload('res://addons/Wol/core/Constants.gd')
|
const Constants = preload('res://addons/Wol/core/Constants.gd')
|
||||||
|
|
||||||
const NULL_STRING = 'null'
|
|
||||||
const FALSE_STRING = 'false'
|
|
||||||
const TRUE_STRING = 'true'
|
|
||||||
const NANI = 'NaN'
|
const NANI = 'NaN'
|
||||||
|
|
||||||
var type = Constants.ValueType.Nullean
|
var type = Constants.ValueType.Nullean
|
||||||
|
@ -74,7 +71,7 @@ func set_value(value):
|
||||||
|
|
||||||
func add(other):
|
func add(other):
|
||||||
if type == Constants.ValueType.Str or other.type == Constants.ValueType.Str:
|
if type == Constants.ValueType.Str or other.type == Constants.ValueType.Str:
|
||||||
return get_script().new('%s%s'%[value(),other.value()])
|
return get_script().new('%s%s' % [value(), other.value()])
|
||||||
if type == Constants.ValueType.Number and other.type == Constants.ValueType.Number:
|
if type == Constants.ValueType.Number and other.type == Constants.ValueType.Number:
|
||||||
return get_script().new(number + other.number)
|
return get_script().new(number + other.number)
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -7,24 +7,53 @@ position: 0, 0
|
||||||
<<command_with multiple arguments>>
|
<<command_with multiple arguments>>
|
||||||
|
|
||||||
// remove "to" to trigger error
|
// remove "to" to trigger error
|
||||||
<<set $direction to 'this'>>
|
<<set $direction to 'that'>>
|
||||||
<<set $one to 1>>
|
<<set $one to 1>>
|
||||||
|
|
||||||
// Implement inline expressions
|
// Implement inline expressions
|
||||||
Bob: Theresa, {$direction} way! #line:5d7a7c
|
<<if visit_count() == 1>>
|
||||||
Theresa: Did you know one + one equals {$one + $one}?
|
Narrator: You, {$direction} way!
|
||||||
Bob: You wanna go somewhere?
|
<<endif>>
|
||||||
|
Narrator: Do you know you've been here {visit_count()} times?
|
||||||
|
You: Did you know one + one equals {$one + $one}?
|
||||||
|
Narrator: You wanna go somewhere?
|
||||||
|
|
||||||
[[Go to the store|TheStore]]
|
-> Go to the store
|
||||||
[[Lets stay here and talk|Talk]]
|
[[TheStore]]
|
||||||
|
// -> Wait, how many times have I been to the store?
|
||||||
|
// Narrator: You've been to the store {visit_count('TheStore')} times.
|
||||||
|
// [[Start]]
|
||||||
|
-> Lets stay here and talk
|
||||||
|
[[Talk]]
|
||||||
===
|
===
|
||||||
title: TheStore
|
title: TheStore
|
||||||
tags:
|
tags:
|
||||||
colorID: 0
|
colorID: 0
|
||||||
position: 0, 200
|
position: 0, 200
|
||||||
---
|
---
|
||||||
Clerk: Welcome to the store.
|
Guy: Hey what's up I need your help can you come here?
|
||||||
Clerk: Can I help you with anything?
|
You: Well I can't I'm buying clothes.
|
||||||
|
All right well hurry up and come over here.
|
||||||
|
You: I can't find them.
|
||||||
|
Guy: What do you mean you can't find them?
|
||||||
|
You: I can't find them there's only soup.
|
||||||
|
Guy: What do you mean there's only soup?!
|
||||||
|
You: It means there's only soup.
|
||||||
|
Guy: WELL THEN GET OUT OF THE SOUP ISLE!!
|
||||||
|
You: Alright you dont have to shout at me!
|
||||||
|
You: There's more soup.
|
||||||
|
Guy: What do you mean there's more soup?
|
||||||
|
You: There's just more soup.
|
||||||
|
Guy: Then go to the next aisle!
|
||||||
|
You: There's still soup!
|
||||||
|
Guy: Where are you right now?!
|
||||||
|
You: I'm at soup!
|
||||||
|
Guy: What do you mean you're at soup?!
|
||||||
|
You: I mean I'm at soup.
|
||||||
|
Guy: WHAT STORE ARE YOU IN?!
|
||||||
|
You: IM AT THE SOUP STORE!!
|
||||||
|
Guy: WHY ARE YOU BUYING CLOTHES AT THE SOUP STORE?!
|
||||||
|
You: FUCK YOU!
|
||||||
[[Go home|Start]]
|
[[Go home|Start]]
|
||||||
===
|
===
|
||||||
title: Talk
|
title: Talk
|
||||||
|
@ -32,9 +61,9 @@ tags:
|
||||||
colorID: 0
|
colorID: 0
|
||||||
position: 0, 400
|
position: 0, 400
|
||||||
---
|
---
|
||||||
Bob: So how are you really?
|
Narrator: So how are you really?
|
||||||
Theresa: I'm good!
|
You: I'm good!
|
||||||
Bob: Do you want to continue talking?
|
Narrator: Do you want to continue talking?
|
||||||
-> Yes
|
-> Yes
|
||||||
[[Start]]
|
[[Start]]
|
||||||
-> No
|
-> No
|
||||||
|
|
|
@ -9,30 +9,12 @@
|
||||||
config_version=4
|
config_version=4
|
||||||
|
|
||||||
_global_script_classes=[ {
|
_global_script_classes=[ {
|
||||||
"base": "Object",
|
|
||||||
"class": "Compiler",
|
|
||||||
"language": "GDScript",
|
|
||||||
"path": "res://addons/Wol/core/compiler/Compiler.gd"
|
|
||||||
}, {
|
|
||||||
"base": "Object",
|
|
||||||
"class": "Lexer",
|
|
||||||
"language": "GDScript",
|
|
||||||
"path": "res://addons/Wol/core/compiler/Lexer.gd"
|
|
||||||
}, {
|
|
||||||
"base": "Object",
|
|
||||||
"class": "Program",
|
|
||||||
"language": "GDScript",
|
|
||||||
"path": "res://addons/Wol/core/Program.gd"
|
|
||||||
}, {
|
|
||||||
"base": "Node",
|
"base": "Node",
|
||||||
"class": "Wol",
|
"class": "Wol",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://addons/Wol/Wol.gd"
|
"path": "res://addons/Wol/Wol.gd"
|
||||||
} ]
|
} ]
|
||||||
_global_script_class_icons={
|
_global_script_class_icons={
|
||||||
"Compiler": "",
|
|
||||||
"Lexer": "",
|
|
||||||
"Program": "",
|
|
||||||
"Wol": ""
|
"Wol": ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue