class Object
Constants
- QVM
Evaluation ##
- QuarkError
Boilerplate ##
Public Instance Methods
apply_core_func(name, vm)
click to toggle source
# File lib/qeval.rb, line 16 def apply_core_func(name, vm) eq, expected, got = type_check(vm.stack, $core_func_type[name]) raise(QuarkError, "Type error with function #{name}\n expected a stack of #{expected}\n but got #{got}") if not eq $core_func[name].call(vm) end
apply_runtime_func(name, vm)
click to toggle source
# File lib/qeval.rb, line 22 def apply_runtime_func(name, vm) quote = vm.bindings[name] vm.program.unshift(*[quote, QAtom.new('call')]) end
deep_clone(x)
click to toggle source
# File lib/qeval.rb, line 42 def deep_clone x Marshal.load(Marshal.dump(x)) end
def_cf(name, type_sig, &code)
click to toggle source
# File lib/qeval.rb, line 11 def def_cf(name, type_sig, &code) $core_func_type[name] = type_sig $core_func[name] = code end
pattern_match(stack_args, args)
click to toggle source
# File lib/qeval.rb, line 27 def pattern_match(stack_args, args) return false if stack_args.length < args.length return {} if args.length == 0 bindings = {} args.zip(stack_args).each do |a, s| if a.is_a? QAtom return false if (bindings.has_key? a.val) && (bindings[a.val] != s) bindings[a.val] = s else return false if a != s end end return bindings end
qparse(str)
click to toggle source
# File lib/qparse.rb, line 37 def qparse str parsed = QuarkParse.new.parse(str) QuarkTransform.new.apply parsed rescue Parslet::ParseFailed => e e.cause.ascii_tree end
qreduce(vm)
click to toggle source
# File lib/qrun.rb, line 13 def qreduce vm until vm.program.empty? item = vm.program.shift if item.is_a? QAtom f_name = item.val.strip if $core_func.has_key? f_name apply_core_func(f_name, vm) elsif vm.bindings.has_key? f_name quote = vm.bindings[f_name] vm.program.unshift(*[quote.dup, QAtom.new('call')]) else raise QuarkError, "No such function: #{f_name}" end else vm.stack.push item end end return vm end
qrepl(vm)
click to toggle source
# File lib/qrun.rb, line 33 def qrepl(vm) loop do print ':> ' begin input = $stdin.gets.chomp case input.strip when '*q' exit! when '*f' vm.bindings.sort.each { |k, v| puts "#{k}\n #{v.to_s}\n\n"} when /\*f\s+(.+)/ if vm.bindings.has_key? $1 puts vm.bindings[$1] else puts "No such function: #{$1}" end else vm = qrun(input, vm.stack.dup, vm.bindings.dup) end puts vm.stack.map { |x| x.is_a?(QQuote) ? x.to_s(20) : x.to_s }.join(' ') rescue Exception => e puts e end end end
qrun(str, stack=[], bindings={})
click to toggle source
# File lib/qrun.rb, line 9 def qrun(str, stack=[], bindings={}) qreduce QVM.new(stack, qparse(str), bindings) end
type_check(stack, type_sig)
click to toggle source
matches a type signature against a data stack
# File lib/qtypes.rb, line 126 def type_check(stack, type_sig) return false if stack.length < type_sig.length return true if type_sig.length == 0 stack_type = stack.last(type_sig.length).map(&:qtype) types_eq = type_sig.zip(stack_type) .map { |sig, type| type_match(sig, type) } .inject(true) { |a, b| a && b} return types_eq, type_sig, stack_type end
type_match(a, b)
click to toggle source
compares two qtype to see if they are equivelent type comparison is not symmetric ‘a` is the signature type, so (:Any, :Empty) will match, but (:Empty, :Any) won’t
# File lib/qtypes.rb, line 120 def type_match(a, b) return true if a == :Any a == b end
type_to_qitem(t)
click to toggle source
converts a qtype to a qitem representation (used in the ‘type` function)
# File lib/qtypes.rb, line 137 def type_to_qitem t return QSym.new(t.to_s) end