123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 | -- Custom implementations of table methods
import FnType, OptionalType, ListType, NilType, String, Bool, Int from require 'types'
import log, viz, node_assert, node_error, each_tag, context_err from require 'util'
types = {
copy: => FnType({@}, @, {"table"})
equal_entries: => FnType({@,@}, Bool, {"table","other"})
set: => FnType({@,@key_type,@value_type}, NilType, {"table","key","value"})
set_all: => FnType({@, @}, NilType, {"table","other"})
get: => FnType({@,@key_type}, OptionalType(@value_type), {"table","key"})
get_or_fail: => FnType({@,@key_type}, @key_type, {"table","key"})
update: => FnType({@,@key_type,FnType({OptionalType(@value_type)},@value_type,nil)}, NilType, {"table","key","fn"})
remove: => FnType({@,@key_type}, NilType, {"table","key"})
pop: => FnType({@,@key_type}, OptionalType(@value_type), {"table","key"})
}
to_table_format = (code, t, reg, dest_reg)->
if t.base_type == "s" or t.base_type == "d"
code\add "#{dest_reg} =l cast #{reg}\n"
code\add "#{dest_reg} =l xor #{dest_reg}, #{t.nil_value}\n"
else
if t.bytes == 8
code\add "#{dest_reg} =l copy #{reg}\n"
else
code\add "#{dest_reg} =l extu#{t.abi_type} #{reg}\n"
if t.nil_value != 0
-- Swap nil_value and 0:
do_toggle,done = code\fresh_labels "do_toggle","done"
is_zero,is_nil,needs_toggle = code\fresh_locals "is_zero","is_nil","needs_toggle"
code\add "#{is_zero} =w ceq#{t.base_type} #{reg}, 0\n"
code\add "#{is_nil} =w ceq#{t.base_type} #{reg}, 0\n"
code\add "#{needs_toggle} =w or #{is_zero}, #{is_nil}\n"
code\add "jnz #{needs_toggle}, #{do_toggle}, #{done}\n"
code\add "#{do_toggle}\n"
code\add "#{dest_reg} =l xor #{dest_reg}, #{t.nil_value}\n"
code\add "#{done}\n"
from_table_format = to_table_format
get = (code, fail_on_missing)=>
table,key = if @__tag == "IndexedTerm"
@value, @index
else
@fn.value, @[1]
t = table.__type
code\add "\n# Table Get\n"
table_reg, key_reg = code\add_values table, key
value_bits, key_bits, value = code\fresh_locals "value.bits", "key.bits", "value"
if t.key_type.base_type == "s" or t.key_type.base_type == "d"
code\add "#{key_bits} =l cast #{key_reg}\n"
else
code\add "#{key_bits} =l copy #{key_reg}\n"
code\add "#{value_bits} =l call $bl_table_get(l #{table_reg}, l #{key_bits}, l #{t.key_type.nil_value}, l #{t.value_type.nil_value})\n"
if t.value_type.base_type == "s" or t.value_type.base_type == "d"
code\add "#{value} =#{t.value_type.base_type} cast #{value_bits}\n"
else
code\add "#{value} =#{t.value_type.base_type} copy #{value_bits}\n"
if fail_on_missing
is_nil = code\fresh_locals "is_nil"
if t.value_type.base_type == "d"
code\add "#{is_nil} =w cuod #{value}, d_0.0 # Test for NaN\n"
elseif t.value_type.base_type == "s"
code\add "#{is_nil} =w cuos #{value}, s_0.0 # Test for NaN\n"
else
code\add "#{is_nil} =w ceq#{t.value_type.base_type} #{value}, #{t.value_type.nil_value}\n"
nil_label,done_label = code\fresh_labels "is_nil", "nonnil"
code\add "jnz #{is_nil}, #{nil_label}, #{done_label}\n"
code\add "#{nil_label}\n"
key_str = code\fresh_locals "key_str"
code\add "#{key_str} =l call #{code\get_tostring_fn(t.key_type)}(#{t.key_type.base_type} #{key_reg}, l 0)\n"
code\add "call $dprintf(l 2, l #{code\get_string_reg(context_err(key, "Key is not present in this table: %s", 2).."\n", "index_error")}, l #{key_str})\n"
code\add "call $_exit(l 1)\n"
code\add "jmp #{nil_label}\n"
code\add "#{done_label}\n"
return value
maybe_reg_to_reg = (code, val)->
if type(val) == 'string'
return val
else
return code\add_value(val)
methods = {
get: (code)=> get(@, code, false)
get_or_fail: (code)=> get(@, code, true)
set: (code,skip_ret,table_t=nil)=>
code\add "\n# Table set\n"
table,key,value = if @__tag == "FnCall"
@fn.value, @[1], @[2]
else
@[1],@[2],@[3]
key_t,value_t = if table_t
table_t.key_type, table_t.value_type
else
key.__type, value.__type
table_reg = maybe_reg_to_reg(code, table)
key_reg = maybe_reg_to_reg(code, key)
value_reg = maybe_reg_to_reg(code, value)
value_bits, key_bits = code\fresh_locals "value.bits", "key.bits"
if key_t.base_type == "s" or key_t.base_type == "d"
code\add "#{key_bits} =l cast #{key_reg}\n"
else
code\add "#{key_bits} =l copy #{key_reg}\n"
if value_t.base_type == "s" or value_t.base_type == "d"
code\add "#{value_bits} =l cast #{value_reg}\n"
else
code\add "#{value_bits} =l copy #{value_reg}\n"
code\add "#{value_bits} =l call $bl_table_set(l #{table_reg}, l #{key_bits}, l #{value_bits}, l #{key_t.nil_value}, l #{value_t.nil_value})\n"
return
copy: (code)=>
copy = code\fresh_locals "copy"
table_reg = code\add_value @[1]
code\add "#{copy} =l call $hashmap_copy(l #{table_reg})\n"
return copy
}
return {:methods, :types, :to_table_format, :from_table_format}
|