Various cleanup to type system
- Make struct into a type constuctor - Rework placeholders - Got rid of 'PrimitiveType' as a concept - Moved out the prelude to its own folder Still in idea form [skip-ci]
This commit is contained in:
parent
d6b483581b
commit
3d491b7a36
@ -5,9 +5,8 @@ It's intented to be a "any color, as long as it's black" kind of renderer
|
|||||||
"""
|
"""
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
|
||||||
from . import ourlang
|
from . import ourlang, prelude
|
||||||
from .type3 import types as type3types
|
from .type3 import placeholders as type3placeholders
|
||||||
from .type3.types import TYPE3_ASSERTION_ERROR, Type3, Type3OrPlaceholder
|
|
||||||
|
|
||||||
|
|
||||||
def phasm_render(inp: ourlang.Module) -> str:
|
def phasm_render(inp: ourlang.Module) -> str:
|
||||||
@ -18,13 +17,14 @@ def phasm_render(inp: ourlang.Module) -> str:
|
|||||||
|
|
||||||
Statements = Generator[str, None, None]
|
Statements = Generator[str, None, None]
|
||||||
|
|
||||||
def type3(inp: Type3OrPlaceholder) -> str:
|
def type3(inp: type3placeholders.Type3OrPlaceholder) -> str:
|
||||||
"""
|
"""
|
||||||
Render: type's name
|
Render: type's name
|
||||||
"""
|
"""
|
||||||
assert isinstance(inp, Type3), TYPE3_ASSERTION_ERROR
|
if isinstance(inp, type3placeholders.PlaceholderForType):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
if inp is type3types.none:
|
if inp is prelude.none:
|
||||||
return 'None'
|
return 'None'
|
||||||
|
|
||||||
return inp.name
|
return inp.name
|
||||||
@ -33,8 +33,11 @@ def struct_definition(inp: ourlang.StructDefinition) -> str:
|
|||||||
"""
|
"""
|
||||||
Render: TypeStruct's definition
|
Render: TypeStruct's definition
|
||||||
"""
|
"""
|
||||||
|
st_args = prelude.struct.did_construct(inp.struct_type3)
|
||||||
|
assert st_args is not None
|
||||||
|
|
||||||
result = f'class {inp.struct_type3.name}:\n'
|
result = f'class {inp.struct_type3.name}:\n'
|
||||||
for mem, typ in inp.struct_type3.members.items():
|
for mem, typ in st_args.items():
|
||||||
result += f' {mem}: {type3(typ)}\n'
|
result += f' {mem}: {type3(typ)}\n'
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@ -4,10 +4,11 @@ This module contains the code to convert parsed Ourlang into WebAssembly code
|
|||||||
import struct
|
import struct
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
from . import codestyle, ourlang, wasm
|
from . import codestyle, ourlang, prelude, wasm
|
||||||
from .runtime import calculate_alloc_size, calculate_member_offset
|
from .runtime import calculate_alloc_size, calculate_member_offset
|
||||||
from .stdlib import alloc as stdlib_alloc
|
from .stdlib import alloc as stdlib_alloc
|
||||||
from .stdlib import types as stdlib_types
|
from .stdlib import types as stdlib_types
|
||||||
|
from .type3 import placeholders as type3placeholders
|
||||||
from .type3 import typeclasses as type3classes
|
from .type3 import typeclasses as type3classes
|
||||||
from .type3 import types as type3types
|
from .type3 import types as type3types
|
||||||
from .wasmgenerator import Generator as WasmGenerator
|
from .wasmgenerator import Generator as WasmGenerator
|
||||||
@ -29,7 +30,7 @@ LOAD_STORE_TYPE_MAP = {
|
|||||||
# For now this is nice & clean, but this will get messy quick
|
# For now this is nice & clean, but this will get messy quick
|
||||||
# Especially once we get functions with polymorphying applied types
|
# Especially once we get functions with polymorphying applied types
|
||||||
INSTANCES = {
|
INSTANCES = {
|
||||||
type3classes.Eq.operators['==']: {
|
prelude.Eq.operators['==']: {
|
||||||
'a=u8': stdlib_types.u8_eq_equals,
|
'a=u8': stdlib_types.u8_eq_equals,
|
||||||
'a=u32': stdlib_types.u32_eq_equals,
|
'a=u32': stdlib_types.u32_eq_equals,
|
||||||
'a=u64': stdlib_types.u64_eq_equals,
|
'a=u64': stdlib_types.u64_eq_equals,
|
||||||
@ -39,7 +40,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_eq_equals,
|
'a=f32': stdlib_types.f32_eq_equals,
|
||||||
'a=f64': stdlib_types.f64_eq_equals,
|
'a=f64': stdlib_types.f64_eq_equals,
|
||||||
},
|
},
|
||||||
type3classes.Eq.operators['!=']: {
|
prelude.Eq.operators['!=']: {
|
||||||
'a=u8': stdlib_types.u8_eq_not_equals,
|
'a=u8': stdlib_types.u8_eq_not_equals,
|
||||||
'a=u32': stdlib_types.u32_eq_not_equals,
|
'a=u32': stdlib_types.u32_eq_not_equals,
|
||||||
'a=u64': stdlib_types.u64_eq_not_equals,
|
'a=u64': stdlib_types.u64_eq_not_equals,
|
||||||
@ -49,7 +50,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_eq_not_equals,
|
'a=f32': stdlib_types.f32_eq_not_equals,
|
||||||
'a=f64': stdlib_types.f64_eq_not_equals,
|
'a=f64': stdlib_types.f64_eq_not_equals,
|
||||||
},
|
},
|
||||||
type3classes.Ord.methods['min']: {
|
prelude.Ord.methods['min']: {
|
||||||
'a=u8': stdlib_types.u8_ord_min,
|
'a=u8': stdlib_types.u8_ord_min,
|
||||||
'a=u32': stdlib_types.u32_ord_min,
|
'a=u32': stdlib_types.u32_ord_min,
|
||||||
'a=u64': stdlib_types.u64_ord_min,
|
'a=u64': stdlib_types.u64_ord_min,
|
||||||
@ -59,7 +60,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_ord_min,
|
'a=f32': stdlib_types.f32_ord_min,
|
||||||
'a=f64': stdlib_types.f64_ord_min,
|
'a=f64': stdlib_types.f64_ord_min,
|
||||||
},
|
},
|
||||||
type3classes.Ord.methods['max']: {
|
prelude.Ord.methods['max']: {
|
||||||
'a=u8': stdlib_types.u8_ord_max,
|
'a=u8': stdlib_types.u8_ord_max,
|
||||||
'a=u32': stdlib_types.u32_ord_max,
|
'a=u32': stdlib_types.u32_ord_max,
|
||||||
'a=u64': stdlib_types.u64_ord_max,
|
'a=u64': stdlib_types.u64_ord_max,
|
||||||
@ -69,7 +70,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_ord_max,
|
'a=f32': stdlib_types.f32_ord_max,
|
||||||
'a=f64': stdlib_types.f64_ord_max,
|
'a=f64': stdlib_types.f64_ord_max,
|
||||||
},
|
},
|
||||||
type3classes.Ord.operators['<']: {
|
prelude.Ord.operators['<']: {
|
||||||
'a=u8': stdlib_types.u8_ord_less_than,
|
'a=u8': stdlib_types.u8_ord_less_than,
|
||||||
'a=u32': stdlib_types.u32_ord_less_than,
|
'a=u32': stdlib_types.u32_ord_less_than,
|
||||||
'a=u64': stdlib_types.u64_ord_less_than,
|
'a=u64': stdlib_types.u64_ord_less_than,
|
||||||
@ -79,7 +80,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_ord_less_than,
|
'a=f32': stdlib_types.f32_ord_less_than,
|
||||||
'a=f64': stdlib_types.f64_ord_less_than,
|
'a=f64': stdlib_types.f64_ord_less_than,
|
||||||
},
|
},
|
||||||
type3classes.Ord.operators['<=']: {
|
prelude.Ord.operators['<=']: {
|
||||||
'a=u8': stdlib_types.u8_ord_less_than_or_equal,
|
'a=u8': stdlib_types.u8_ord_less_than_or_equal,
|
||||||
'a=u32': stdlib_types.u32_ord_less_than_or_equal,
|
'a=u32': stdlib_types.u32_ord_less_than_or_equal,
|
||||||
'a=u64': stdlib_types.u64_ord_less_than_or_equal,
|
'a=u64': stdlib_types.u64_ord_less_than_or_equal,
|
||||||
@ -89,7 +90,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_ord_less_than_or_equal,
|
'a=f32': stdlib_types.f32_ord_less_than_or_equal,
|
||||||
'a=f64': stdlib_types.f64_ord_less_than_or_equal,
|
'a=f64': stdlib_types.f64_ord_less_than_or_equal,
|
||||||
},
|
},
|
||||||
type3classes.Ord.operators['>']: {
|
prelude.Ord.operators['>']: {
|
||||||
'a=u8': stdlib_types.u8_ord_greater_than,
|
'a=u8': stdlib_types.u8_ord_greater_than,
|
||||||
'a=u32': stdlib_types.u32_ord_greater_than,
|
'a=u32': stdlib_types.u32_ord_greater_than,
|
||||||
'a=u64': stdlib_types.u64_ord_greater_than,
|
'a=u64': stdlib_types.u64_ord_greater_than,
|
||||||
@ -99,7 +100,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_ord_greater_than,
|
'a=f32': stdlib_types.f32_ord_greater_than,
|
||||||
'a=f64': stdlib_types.f64_ord_greater_than,
|
'a=f64': stdlib_types.f64_ord_greater_than,
|
||||||
},
|
},
|
||||||
type3classes.Ord.operators['>=']: {
|
prelude.Ord.operators['>=']: {
|
||||||
'a=u8': stdlib_types.u8_ord_greater_than_or_equal,
|
'a=u8': stdlib_types.u8_ord_greater_than_or_equal,
|
||||||
'a=u32': stdlib_types.u32_ord_greater_than_or_equal,
|
'a=u32': stdlib_types.u32_ord_greater_than_or_equal,
|
||||||
'a=u64': stdlib_types.u64_ord_greater_than_or_equal,
|
'a=u64': stdlib_types.u64_ord_greater_than_or_equal,
|
||||||
@ -109,90 +110,90 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_ord_greater_than_or_equal,
|
'a=f32': stdlib_types.f32_ord_greater_than_or_equal,
|
||||||
'a=f64': stdlib_types.f64_ord_greater_than_or_equal,
|
'a=f64': stdlib_types.f64_ord_greater_than_or_equal,
|
||||||
},
|
},
|
||||||
type3classes.Bits.methods['shl']: {
|
prelude.Bits.methods['shl']: {
|
||||||
'a=u8': stdlib_types.u8_bits_logical_shift_left,
|
'a=u8': stdlib_types.u8_bits_logical_shift_left,
|
||||||
'a=u32': stdlib_types.u32_bits_logical_shift_left,
|
'a=u32': stdlib_types.u32_bits_logical_shift_left,
|
||||||
'a=u64': stdlib_types.u64_bits_logical_shift_left,
|
'a=u64': stdlib_types.u64_bits_logical_shift_left,
|
||||||
},
|
},
|
||||||
type3classes.Bits.methods['shr']: {
|
prelude.Bits.methods['shr']: {
|
||||||
'a=u8': stdlib_types.u8_bits_logical_shift_right,
|
'a=u8': stdlib_types.u8_bits_logical_shift_right,
|
||||||
'a=u32': stdlib_types.u32_bits_logical_shift_right,
|
'a=u32': stdlib_types.u32_bits_logical_shift_right,
|
||||||
'a=u64': stdlib_types.u64_bits_logical_shift_right,
|
'a=u64': stdlib_types.u64_bits_logical_shift_right,
|
||||||
},
|
},
|
||||||
type3classes.Bits.methods['rotl']: {
|
prelude.Bits.methods['rotl']: {
|
||||||
'a=u8': stdlib_types.u8_bits_rotate_left,
|
'a=u8': stdlib_types.u8_bits_rotate_left,
|
||||||
'a=u32': stdlib_types.u32_bits_rotate_left,
|
'a=u32': stdlib_types.u32_bits_rotate_left,
|
||||||
'a=u64': stdlib_types.u64_bits_rotate_left,
|
'a=u64': stdlib_types.u64_bits_rotate_left,
|
||||||
},
|
},
|
||||||
type3classes.Bits.methods['rotr']: {
|
prelude.Bits.methods['rotr']: {
|
||||||
'a=u8': stdlib_types.u8_bits_rotate_right,
|
'a=u8': stdlib_types.u8_bits_rotate_right,
|
||||||
'a=u32': stdlib_types.u32_bits_rotate_right,
|
'a=u32': stdlib_types.u32_bits_rotate_right,
|
||||||
'a=u64': stdlib_types.u64_bits_rotate_right,
|
'a=u64': stdlib_types.u64_bits_rotate_right,
|
||||||
},
|
},
|
||||||
type3classes.Bits.operators['&']: {
|
prelude.Bits.operators['&']: {
|
||||||
'a=u8': stdlib_types.u8_bits_bitwise_and,
|
'a=u8': stdlib_types.u8_bits_bitwise_and,
|
||||||
'a=u32': stdlib_types.u32_bits_bitwise_and,
|
'a=u32': stdlib_types.u32_bits_bitwise_and,
|
||||||
'a=u64': stdlib_types.u64_bits_bitwise_and,
|
'a=u64': stdlib_types.u64_bits_bitwise_and,
|
||||||
},
|
},
|
||||||
type3classes.Bits.operators['|']: {
|
prelude.Bits.operators['|']: {
|
||||||
'a=u8': stdlib_types.u8_bits_bitwise_or,
|
'a=u8': stdlib_types.u8_bits_bitwise_or,
|
||||||
'a=u32': stdlib_types.u32_bits_bitwise_or,
|
'a=u32': stdlib_types.u32_bits_bitwise_or,
|
||||||
'a=u64': stdlib_types.u64_bits_bitwise_or,
|
'a=u64': stdlib_types.u64_bits_bitwise_or,
|
||||||
},
|
},
|
||||||
type3classes.Bits.operators['^']: {
|
prelude.Bits.operators['^']: {
|
||||||
'a=u8': stdlib_types.u8_bits_bitwise_xor,
|
'a=u8': stdlib_types.u8_bits_bitwise_xor,
|
||||||
'a=u32': stdlib_types.u32_bits_bitwise_xor,
|
'a=u32': stdlib_types.u32_bits_bitwise_xor,
|
||||||
'a=u64': stdlib_types.u64_bits_bitwise_xor,
|
'a=u64': stdlib_types.u64_bits_bitwise_xor,
|
||||||
},
|
},
|
||||||
type3classes.Floating.methods['sqrt']: {
|
prelude.Floating.methods['sqrt']: {
|
||||||
'a=f32': stdlib_types.f32_floating_sqrt,
|
'a=f32': stdlib_types.f32_floating_sqrt,
|
||||||
'a=f64': stdlib_types.f64_floating_sqrt,
|
'a=f64': stdlib_types.f64_floating_sqrt,
|
||||||
},
|
},
|
||||||
type3classes.Fractional.methods['ceil']: {
|
prelude.Fractional.methods['ceil']: {
|
||||||
'a=f32': stdlib_types.f32_fractional_ceil,
|
'a=f32': stdlib_types.f32_fractional_ceil,
|
||||||
'a=f64': stdlib_types.f64_fractional_ceil,
|
'a=f64': stdlib_types.f64_fractional_ceil,
|
||||||
},
|
},
|
||||||
type3classes.Fractional.methods['floor']: {
|
prelude.Fractional.methods['floor']: {
|
||||||
'a=f32': stdlib_types.f32_fractional_floor,
|
'a=f32': stdlib_types.f32_fractional_floor,
|
||||||
'a=f64': stdlib_types.f64_fractional_floor,
|
'a=f64': stdlib_types.f64_fractional_floor,
|
||||||
},
|
},
|
||||||
type3classes.Fractional.methods['trunc']: {
|
prelude.Fractional.methods['trunc']: {
|
||||||
'a=f32': stdlib_types.f32_fractional_trunc,
|
'a=f32': stdlib_types.f32_fractional_trunc,
|
||||||
'a=f64': stdlib_types.f64_fractional_trunc,
|
'a=f64': stdlib_types.f64_fractional_trunc,
|
||||||
},
|
},
|
||||||
type3classes.Fractional.methods['nearest']: {
|
prelude.Fractional.methods['nearest']: {
|
||||||
'a=f32': stdlib_types.f32_fractional_nearest,
|
'a=f32': stdlib_types.f32_fractional_nearest,
|
||||||
'a=f64': stdlib_types.f64_fractional_nearest,
|
'a=f64': stdlib_types.f64_fractional_nearest,
|
||||||
},
|
},
|
||||||
type3classes.Fractional.operators['/']: {
|
prelude.Fractional.operators['/']: {
|
||||||
'a=f32': stdlib_types.f32_fractional_div,
|
'a=f32': stdlib_types.f32_fractional_div,
|
||||||
'a=f64': stdlib_types.f64_fractional_div,
|
'a=f64': stdlib_types.f64_fractional_div,
|
||||||
},
|
},
|
||||||
type3classes.Integral.operators['//']: {
|
prelude.Integral.operators['//']: {
|
||||||
'a=u32': stdlib_types.u32_integral_div,
|
'a=u32': stdlib_types.u32_integral_div,
|
||||||
'a=u64': stdlib_types.u64_integral_div,
|
'a=u64': stdlib_types.u64_integral_div,
|
||||||
'a=i32': stdlib_types.i32_integral_div,
|
'a=i32': stdlib_types.i32_integral_div,
|
||||||
'a=i64': stdlib_types.i64_integral_div,
|
'a=i64': stdlib_types.i64_integral_div,
|
||||||
},
|
},
|
||||||
type3classes.Integral.operators['%']: {
|
prelude.Integral.operators['%']: {
|
||||||
'a=u32': stdlib_types.u32_integral_rem,
|
'a=u32': stdlib_types.u32_integral_rem,
|
||||||
'a=u64': stdlib_types.u64_integral_rem,
|
'a=u64': stdlib_types.u64_integral_rem,
|
||||||
'a=i32': stdlib_types.i32_integral_rem,
|
'a=i32': stdlib_types.i32_integral_rem,
|
||||||
'a=i64': stdlib_types.i64_integral_rem,
|
'a=i64': stdlib_types.i64_integral_rem,
|
||||||
},
|
},
|
||||||
type3classes.IntNum.methods['abs']: {
|
prelude.IntNum.methods['abs']: {
|
||||||
'a=i32': stdlib_types.i32_intnum_abs,
|
'a=i32': stdlib_types.i32_intnum_abs,
|
||||||
'a=i64': stdlib_types.i64_intnum_abs,
|
'a=i64': stdlib_types.i64_intnum_abs,
|
||||||
'a=f32': stdlib_types.f32_intnum_abs,
|
'a=f32': stdlib_types.f32_intnum_abs,
|
||||||
'a=f64': stdlib_types.f64_intnum_abs,
|
'a=f64': stdlib_types.f64_intnum_abs,
|
||||||
},
|
},
|
||||||
type3classes.IntNum.methods['neg']: {
|
prelude.IntNum.methods['neg']: {
|
||||||
'a=i32': stdlib_types.i32_intnum_neg,
|
'a=i32': stdlib_types.i32_intnum_neg,
|
||||||
'a=i64': stdlib_types.i64_intnum_neg,
|
'a=i64': stdlib_types.i64_intnum_neg,
|
||||||
'a=f32': stdlib_types.f32_intnum_neg,
|
'a=f32': stdlib_types.f32_intnum_neg,
|
||||||
'a=f64': stdlib_types.f64_intnum_neg,
|
'a=f64': stdlib_types.f64_intnum_neg,
|
||||||
},
|
},
|
||||||
type3classes.NatNum.operators['+']: {
|
prelude.NatNum.operators['+']: {
|
||||||
'a=u32': stdlib_types.u32_natnum_add,
|
'a=u32': stdlib_types.u32_natnum_add,
|
||||||
'a=u64': stdlib_types.u64_natnum_add,
|
'a=u64': stdlib_types.u64_natnum_add,
|
||||||
'a=i32': stdlib_types.i32_natnum_add,
|
'a=i32': stdlib_types.i32_natnum_add,
|
||||||
@ -200,7 +201,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_natnum_add,
|
'a=f32': stdlib_types.f32_natnum_add,
|
||||||
'a=f64': stdlib_types.f64_natnum_add,
|
'a=f64': stdlib_types.f64_natnum_add,
|
||||||
},
|
},
|
||||||
type3classes.NatNum.operators['-']: {
|
prelude.NatNum.operators['-']: {
|
||||||
'a=u32': stdlib_types.u32_natnum_sub,
|
'a=u32': stdlib_types.u32_natnum_sub,
|
||||||
'a=u64': stdlib_types.u64_natnum_sub,
|
'a=u64': stdlib_types.u64_natnum_sub,
|
||||||
'a=i32': stdlib_types.i32_natnum_sub,
|
'a=i32': stdlib_types.i32_natnum_sub,
|
||||||
@ -208,7 +209,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_natnum_sub,
|
'a=f32': stdlib_types.f32_natnum_sub,
|
||||||
'a=f64': stdlib_types.f64_natnum_sub,
|
'a=f64': stdlib_types.f64_natnum_sub,
|
||||||
},
|
},
|
||||||
type3classes.NatNum.operators['*']: {
|
prelude.NatNum.operators['*']: {
|
||||||
'a=u32': stdlib_types.u32_natnum_mul,
|
'a=u32': stdlib_types.u32_natnum_mul,
|
||||||
'a=u64': stdlib_types.u64_natnum_mul,
|
'a=u64': stdlib_types.u64_natnum_mul,
|
||||||
'a=i32': stdlib_types.i32_natnum_mul,
|
'a=i32': stdlib_types.i32_natnum_mul,
|
||||||
@ -216,7 +217,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_natnum_mul,
|
'a=f32': stdlib_types.f32_natnum_mul,
|
||||||
'a=f64': stdlib_types.f64_natnum_mul,
|
'a=f64': stdlib_types.f64_natnum_mul,
|
||||||
},
|
},
|
||||||
type3classes.NatNum.operators['<<']: {
|
prelude.NatNum.operators['<<']: {
|
||||||
'a=u32': stdlib_types.u32_natnum_arithmic_shift_left,
|
'a=u32': stdlib_types.u32_natnum_arithmic_shift_left,
|
||||||
'a=u64': stdlib_types.u64_natnum_arithmic_shift_left,
|
'a=u64': stdlib_types.u64_natnum_arithmic_shift_left,
|
||||||
'a=i32': stdlib_types.i32_natnum_arithmic_shift_left,
|
'a=i32': stdlib_types.i32_natnum_arithmic_shift_left,
|
||||||
@ -224,7 +225,7 @@ INSTANCES = {
|
|||||||
'a=f32': stdlib_types.f32_natnum_arithmic_shift_left,
|
'a=f32': stdlib_types.f32_natnum_arithmic_shift_left,
|
||||||
'a=f64': stdlib_types.f64_natnum_arithmic_shift_left,
|
'a=f64': stdlib_types.f64_natnum_arithmic_shift_left,
|
||||||
},
|
},
|
||||||
type3classes.NatNum.operators['>>']: {
|
prelude.NatNum.operators['>>']: {
|
||||||
'a=u32': stdlib_types.u32_natnum_arithmic_shift_right,
|
'a=u32': stdlib_types.u32_natnum_arithmic_shift_right,
|
||||||
'a=u64': stdlib_types.u64_natnum_arithmic_shift_right,
|
'a=u64': stdlib_types.u64_natnum_arithmic_shift_right,
|
||||||
'a=i32': stdlib_types.i32_natnum_arithmic_shift_right,
|
'a=i32': stdlib_types.i32_natnum_arithmic_shift_right,
|
||||||
@ -241,61 +242,57 @@ def phasm_compile(inp: ourlang.Module) -> wasm.Module:
|
|||||||
"""
|
"""
|
||||||
return module(inp)
|
return module(inp)
|
||||||
|
|
||||||
def type3(inp: type3types.Type3OrPlaceholder) -> wasm.WasmType:
|
def type3(inp: type3placeholders.Type3OrPlaceholder) -> wasm.WasmType:
|
||||||
"""
|
"""
|
||||||
Compile: type
|
Compile: type
|
||||||
|
|
||||||
Types are used for example in WebAssembly function parameters
|
Types are used for example in WebAssembly function parameters
|
||||||
and return types.
|
and return types.
|
||||||
"""
|
"""
|
||||||
assert isinstance(inp, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(inp, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp == type3types.none:
|
if inp == prelude.none:
|
||||||
return wasm.WasmTypeNone()
|
return wasm.WasmTypeNone()
|
||||||
|
|
||||||
if inp == type3types.bool_:
|
if inp == prelude.bool_:
|
||||||
# WebAssembly stores booleans as i32
|
# WebAssembly stores booleans as i32
|
||||||
# See e.g. f32.eq, which is [f32 f32] -> [i32]
|
# See e.g. f32.eq, which is [f32 f32] -> [i32]
|
||||||
return wasm.WasmTypeInt32()
|
return wasm.WasmTypeInt32()
|
||||||
|
|
||||||
if inp == type3types.u8:
|
if inp == prelude.u8:
|
||||||
# WebAssembly has only support for 32 and 64 bits
|
# WebAssembly has only support for 32 and 64 bits
|
||||||
# So we need to store more memory per byte
|
# So we need to store more memory per byte
|
||||||
return wasm.WasmTypeInt32()
|
return wasm.WasmTypeInt32()
|
||||||
|
|
||||||
if inp == type3types.u32:
|
if inp == prelude.u32:
|
||||||
return wasm.WasmTypeInt32()
|
return wasm.WasmTypeInt32()
|
||||||
|
|
||||||
if inp == type3types.u64:
|
if inp == prelude.u64:
|
||||||
return wasm.WasmTypeInt64()
|
return wasm.WasmTypeInt64()
|
||||||
|
|
||||||
if inp == type3types.i8:
|
if inp == prelude.i8:
|
||||||
# WebAssembly has only support for 32 and 64 bits
|
# WebAssembly has only support for 32 and 64 bits
|
||||||
# So we need to store more memory per byte
|
# So we need to store more memory per byte
|
||||||
return wasm.WasmTypeInt32()
|
return wasm.WasmTypeInt32()
|
||||||
|
|
||||||
if inp == type3types.i32:
|
if inp == prelude.i32:
|
||||||
return wasm.WasmTypeInt32()
|
return wasm.WasmTypeInt32()
|
||||||
|
|
||||||
if inp == type3types.i64:
|
if inp == prelude.i64:
|
||||||
return wasm.WasmTypeInt64()
|
return wasm.WasmTypeInt64()
|
||||||
|
|
||||||
if inp == type3types.f32:
|
if inp == prelude.f32:
|
||||||
return wasm.WasmTypeFloat32()
|
return wasm.WasmTypeFloat32()
|
||||||
|
|
||||||
if inp == type3types.f64:
|
if inp == prelude.f64:
|
||||||
return wasm.WasmTypeFloat64()
|
return wasm.WasmTypeFloat64()
|
||||||
|
|
||||||
if inp == type3types.bytes_:
|
if inp == prelude.bytes_:
|
||||||
# bytes are passed as pointer
|
# bytes are passed as pointer
|
||||||
# And pointers are i32
|
# And pointers are i32
|
||||||
return wasm.WasmTypeInt32()
|
return wasm.WasmTypeInt32()
|
||||||
|
|
||||||
if isinstance(inp, type3types.StructType3):
|
if prelude.InternalPassAsPointer in inp.classes:
|
||||||
# Structs are passed as pointer, which are i32
|
|
||||||
return wasm.WasmTypeInt32()
|
|
||||||
|
|
||||||
if type3classes.InternalPassAsPointer in inp.classes:
|
|
||||||
return wasm.WasmTypeInt32()
|
return wasm.WasmTypeInt32()
|
||||||
|
|
||||||
raise NotImplementedError(type3, inp)
|
raise NotImplementedError(type3, inp)
|
||||||
@ -304,17 +301,17 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
|
|||||||
"""
|
"""
|
||||||
Compile: Instantiation (allocation) of a tuple
|
Compile: Instantiation (allocation) of a tuple
|
||||||
"""
|
"""
|
||||||
assert isinstance(inp.type3, type3types.PrimitiveType3)
|
assert isinstance(inp.type3, type3types.Type3)
|
||||||
|
|
||||||
args: list[type3types.PrimitiveType3] = []
|
args: list[type3types.Type3] = []
|
||||||
|
|
||||||
sa_args = type3types.static_array.did_construct(inp.type3)
|
sa_args = prelude.static_array.did_construct(inp.type3)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
args = [sa_type for _ in range(sa_len.value)]
|
args = [sa_type for _ in range(sa_len.value)]
|
||||||
|
|
||||||
if not args:
|
if not args:
|
||||||
tp_args = type3types.tuple_.did_construct(inp.type3)
|
tp_args = prelude.tuple_.did_construct(inp.type3)
|
||||||
if tp_args is None:
|
if tp_args is None:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@ -322,7 +319,7 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
|
|||||||
|
|
||||||
comment_elements = ''
|
comment_elements = ''
|
||||||
for element in inp.elements:
|
for element in inp.elements:
|
||||||
assert isinstance(element.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(element.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
comment_elements += f'{element.type3.name}, '
|
comment_elements += f'{element.type3.name}, '
|
||||||
|
|
||||||
tmp_var = wgn.temp_var_i32('tuple_adr')
|
tmp_var = wgn.temp_var_i32('tuple_adr')
|
||||||
@ -336,19 +333,17 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
|
|||||||
# Store each element individually
|
# Store each element individually
|
||||||
offset = 0
|
offset = 0
|
||||||
for element, exp_type3 in zip(inp.elements, args):
|
for element, exp_type3 in zip(inp.elements, args):
|
||||||
if isinstance(exp_type3, type3types.PlaceholderForType):
|
if isinstance(exp_type3, type3placeholders.PlaceholderForType):
|
||||||
assert exp_type3.resolve_as is not None
|
assert exp_type3.resolve_as is not None
|
||||||
assert isinstance(exp_type3.resolve_as, type3types.PrimitiveType3)
|
assert isinstance(exp_type3.resolve_as, type3types.Type3)
|
||||||
exp_type3 = exp_type3.resolve_as
|
exp_type3 = exp_type3.resolve_as
|
||||||
|
|
||||||
assert element.type3 == exp_type3
|
assert element.type3 == exp_type3
|
||||||
|
|
||||||
if type3classes.InternalPassAsPointer in exp_type3.classes:
|
if prelude.InternalPassAsPointer in exp_type3.classes:
|
||||||
mtyp = 'i32'
|
|
||||||
elif isinstance(exp_type3, type3types.StructType3):
|
|
||||||
mtyp = 'i32'
|
mtyp = 'i32'
|
||||||
else:
|
else:
|
||||||
assert isinstance(exp_type3, type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
|
assert isinstance(exp_type3, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||||
mtyp = LOAD_STORE_TYPE_MAP[exp_type3.name]
|
mtyp = LOAD_STORE_TYPE_MAP[exp_type3.name]
|
||||||
|
|
||||||
wgn.add_statement('nop', comment='PRE')
|
wgn.add_statement('nop', comment='PRE')
|
||||||
@ -371,30 +366,30 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
raise Exception
|
raise Exception
|
||||||
|
|
||||||
if isinstance(inp, ourlang.ConstantPrimitive):
|
if isinstance(inp, ourlang.ConstantPrimitive):
|
||||||
assert isinstance(inp.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp.type3 in (type3types.i8, type3types.u8, ):
|
if inp.type3 in (prelude.i8, prelude.u8, ):
|
||||||
# No native u8 type - treat as i32, with caution
|
# No native u8 type - treat as i32, with caution
|
||||||
assert isinstance(inp.value, int)
|
assert isinstance(inp.value, int)
|
||||||
wgn.i32.const(inp.value)
|
wgn.i32.const(inp.value)
|
||||||
return
|
return
|
||||||
|
|
||||||
if inp.type3 in (type3types.i32, type3types.u32, ):
|
if inp.type3 in (prelude.i32, prelude.u32, ):
|
||||||
assert isinstance(inp.value, int)
|
assert isinstance(inp.value, int)
|
||||||
wgn.i32.const(inp.value)
|
wgn.i32.const(inp.value)
|
||||||
return
|
return
|
||||||
|
|
||||||
if inp.type3 in (type3types.i64, type3types.u64, ):
|
if inp.type3 in (prelude.i64, prelude.u64, ):
|
||||||
assert isinstance(inp.value, int)
|
assert isinstance(inp.value, int)
|
||||||
wgn.i64.const(inp.value)
|
wgn.i64.const(inp.value)
|
||||||
return
|
return
|
||||||
|
|
||||||
if inp.type3 == type3types.f32:
|
if inp.type3 == prelude.f32:
|
||||||
assert isinstance(inp.value, float)
|
assert isinstance(inp.value, float)
|
||||||
wgn.f32.const(inp.value)
|
wgn.f32.const(inp.value)
|
||||||
return
|
return
|
||||||
|
|
||||||
if inp.type3 == type3types.f64:
|
if inp.type3 == prelude.f64:
|
||||||
assert isinstance(inp.value, float)
|
assert isinstance(inp.value, float)
|
||||||
wgn.f64.const(inp.value)
|
wgn.f64.const(inp.value)
|
||||||
return
|
return
|
||||||
@ -412,34 +407,18 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp.variable, ourlang.ModuleConstantDef):
|
if isinstance(inp.variable, ourlang.ModuleConstantDef):
|
||||||
assert isinstance(inp.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if type3classes.InternalPassAsPointer in inp.type3.classes:
|
if prelude.InternalPassAsPointer in inp.type3.classes:
|
||||||
# FIXME: Artifact from older version
|
# FIXME: Artifact from older version
|
||||||
assert isinstance(inp.variable.constant, ourlang.ConstantTuple)
|
assert isinstance(inp.variable.constant, (ourlang.ConstantTuple, ourlang.ConstantStruct, ))
|
||||||
|
|
||||||
address = inp.variable.constant.data_block.address
|
address = inp.variable.constant.data_block.address
|
||||||
assert address is not None, 'Value not allocated'
|
assert address is not None, 'Value not allocated'
|
||||||
wgn.i32.const(address)
|
wgn.i32.const(address)
|
||||||
return
|
return
|
||||||
|
|
||||||
if inp.type3 is type3types.bytes_:
|
if isinstance(inp.type3, type3types.Type3):
|
||||||
assert isinstance(inp.variable.constant, ourlang.ConstantBytes)
|
|
||||||
|
|
||||||
address = inp.variable.constant.data_block.address
|
|
||||||
assert address is not None, 'Value not allocated'
|
|
||||||
wgn.i32.const(address)
|
|
||||||
return
|
|
||||||
|
|
||||||
if isinstance(inp.type3, type3types.StructType3):
|
|
||||||
assert isinstance(inp.variable.constant, ourlang.ConstantStruct)
|
|
||||||
|
|
||||||
address = inp.variable.constant.data_block.address
|
|
||||||
assert address is not None, 'Value not allocated'
|
|
||||||
wgn.i32.const(address)
|
|
||||||
return
|
|
||||||
|
|
||||||
if isinstance(inp.type3, type3types.PrimitiveType3):
|
|
||||||
expression(wgn, inp.variable.constant)
|
expression(wgn, inp.variable.constant)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -451,7 +430,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
expression(wgn, inp.left)
|
expression(wgn, inp.left)
|
||||||
expression(wgn, inp.right)
|
expression(wgn, inp.right)
|
||||||
|
|
||||||
assert isinstance(inp.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
type_var_map: Dict[type3classes.TypeVariable, type3types.Type3] = {}
|
type_var_map: Dict[type3classes.TypeVariable, type3types.Type3] = {}
|
||||||
|
|
||||||
@ -460,7 +439,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
# Fixed type, not part of the lookup requirements
|
# Fixed type, not part of the lookup requirements
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert isinstance(arg_expr.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(arg_expr.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
type_var_map[type_var] = arg_expr.type3
|
type_var_map[type_var] = arg_expr.type3
|
||||||
|
|
||||||
instance_key = ','.join(
|
instance_key = ','.join(
|
||||||
@ -478,16 +457,16 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
if isinstance(inp, ourlang.UnaryOp):
|
if isinstance(inp, ourlang.UnaryOp):
|
||||||
expression(wgn, inp.right)
|
expression(wgn, inp.right)
|
||||||
|
|
||||||
assert isinstance(inp.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp.type3 == type3types.u32:
|
if inp.type3 == prelude.u32:
|
||||||
if inp.operator == 'len':
|
if inp.operator == 'len':
|
||||||
if inp.right.type3 == type3types.bytes_:
|
if inp.right.type3 == prelude.bytes_:
|
||||||
wgn.i32.load()
|
wgn.i32.load()
|
||||||
return
|
return
|
||||||
|
|
||||||
if inp.operator == 'cast':
|
if inp.operator == 'cast':
|
||||||
if inp.type3 == type3types.u32 and inp.right.type3 == type3types.u8:
|
if inp.type3 == prelude.u32 and inp.right.type3 == prelude.u8:
|
||||||
# Nothing to do, you can use an u8 value as a u32 no problem
|
# Nothing to do, you can use an u8 value as a u32 no problem
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -506,7 +485,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
# Fixed type, not part of the lookup requirements
|
# Fixed type, not part of the lookup requirements
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert isinstance(arg_expr.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(arg_expr.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
type_var_map[type_var] = arg_expr.type3
|
type_var_map[type_var] = arg_expr.type3
|
||||||
|
|
||||||
instance_key = ','.join(
|
instance_key = ','.join(
|
||||||
@ -529,17 +508,17 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.Subscript):
|
if isinstance(inp, ourlang.Subscript):
|
||||||
assert isinstance(inp.varref.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.varref.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp.varref.type3 is type3types.bytes_:
|
if inp.varref.type3 is prelude.bytes_:
|
||||||
expression(wgn, inp.varref)
|
expression(wgn, inp.varref)
|
||||||
expression(wgn, inp.index)
|
expression(wgn, inp.index)
|
||||||
wgn.call(stdlib_types.__subscript_bytes__)
|
wgn.call(stdlib_types.__subscript_bytes__)
|
||||||
return
|
return
|
||||||
|
|
||||||
assert isinstance(inp.varref.type3, type3types.PrimitiveType3)
|
assert isinstance(inp.varref.type3, type3types.Type3)
|
||||||
|
|
||||||
sa_args = type3types.static_array.did_construct(inp.varref.type3)
|
sa_args = prelude.static_array.did_construct(inp.varref.type3)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
el_type, el_len = sa_args
|
el_type, el_len = sa_args
|
||||||
|
|
||||||
@ -563,33 +542,31 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
wgn.i32.mul()
|
wgn.i32.mul()
|
||||||
wgn.i32.add()
|
wgn.i32.add()
|
||||||
|
|
||||||
assert isinstance(el_type, type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
|
assert isinstance(el_type, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||||
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
||||||
|
|
||||||
wgn.add_statement(f'{mtyp}.load')
|
wgn.add_statement(f'{mtyp}.load')
|
||||||
return
|
return
|
||||||
|
|
||||||
tp_args = type3types.tuple_.did_construct(inp.varref.type3)
|
tp_args = prelude.tuple_.did_construct(inp.varref.type3)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
assert isinstance(inp.index, ourlang.ConstantPrimitive)
|
assert isinstance(inp.index, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(inp.index.value, int)
|
assert isinstance(inp.index.value, int)
|
||||||
|
|
||||||
offset = 0
|
offset = 0
|
||||||
for el_type in tp_args[0:inp.index.value]:
|
for el_type in tp_args[0:inp.index.value]:
|
||||||
assert isinstance(el_type, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(el_type, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
offset += calculate_alloc_size(el_type)
|
offset += calculate_alloc_size(el_type)
|
||||||
|
|
||||||
el_type = tp_args[inp.index.value]
|
el_type = tp_args[inp.index.value]
|
||||||
assert isinstance(el_type, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(el_type, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
expression(wgn, inp.varref)
|
expression(wgn, inp.varref)
|
||||||
|
|
||||||
if isinstance(el_type, type3types.StructType3):
|
if prelude.InternalPassAsPointer in el_type.classes:
|
||||||
mtyp = 'i32'
|
|
||||||
elif type3classes.InternalPassAsPointer in el_type.classes:
|
|
||||||
mtyp = 'i32'
|
mtyp = 'i32'
|
||||||
else:
|
else:
|
||||||
assert isinstance(el_type, type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
|
assert isinstance(el_type, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||||
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
||||||
|
|
||||||
wgn.add_statement(f'{mtyp}.load', f'offset={offset}')
|
wgn.add_statement(f'{mtyp}.load', f'offset={offset}')
|
||||||
@ -598,12 +575,19 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
raise NotImplementedError(expression, inp, inp.varref.type3)
|
raise NotImplementedError(expression, inp, inp.varref.type3)
|
||||||
|
|
||||||
if isinstance(inp, ourlang.AccessStructMember):
|
if isinstance(inp, ourlang.AccessStructMember):
|
||||||
assert isinstance(inp.struct_type3.members[inp.member], type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
|
assert isinstance(inp.struct_type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
mtyp = LOAD_STORE_TYPE_MAP[inp.struct_type3.members[inp.member].name]
|
|
||||||
|
st_args = prelude.struct.did_construct(inp.struct_type3)
|
||||||
|
assert st_args is not None
|
||||||
|
|
||||||
|
member_type = st_args[inp.member]
|
||||||
|
|
||||||
|
assert isinstance(member_type, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||||
|
mtyp = LOAD_STORE_TYPE_MAP[member_type.name]
|
||||||
|
|
||||||
expression(wgn, inp.varref)
|
expression(wgn, inp.varref)
|
||||||
wgn.add_statement(f'{mtyp}.load', 'offset=' + str(calculate_member_offset(
|
wgn.add_statement(f'{mtyp}.load', 'offset=' + str(calculate_member_offset(
|
||||||
inp.struct_type3, inp.member
|
inp.struct_type3.name, st_args, inp.member
|
||||||
)))
|
)))
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -617,9 +601,9 @@ def expression_fold(wgn: WasmGenerator, inp: ourlang.Fold) -> None:
|
|||||||
"""
|
"""
|
||||||
Compile: Fold expression
|
Compile: Fold expression
|
||||||
"""
|
"""
|
||||||
assert isinstance(inp.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp.iter.type3 is not type3types.bytes_:
|
if inp.iter.type3 is not prelude.bytes_:
|
||||||
raise NotImplementedError(expression_fold, inp, inp.iter.type3)
|
raise NotImplementedError(expression_fold, inp, inp.iter.type3)
|
||||||
|
|
||||||
wgn.add_statement('nop', comment='acu :: u8')
|
wgn.add_statement('nop', comment='acu :: u8')
|
||||||
@ -848,7 +832,7 @@ def module_data(inp: ourlang.ModuleData) -> bytes:
|
|||||||
data_list: List[bytes] = []
|
data_list: List[bytes] = []
|
||||||
|
|
||||||
for constant in block.data:
|
for constant in block.data:
|
||||||
assert isinstance(constant.type3, type3types.Type3), (id(constant), type3types.TYPE3_ASSERTION_ERROR)
|
assert isinstance(constant.type3, type3types.Type3), (id(constant), type3placeholders.TYPE3_ASSERTION_ERROR)
|
||||||
|
|
||||||
if isinstance(constant, ourlang.ConstantMemoryStored) and block is not constant.data_block:
|
if isinstance(constant, ourlang.ConstantMemoryStored) and block is not constant.data_block:
|
||||||
# It's stored in a different block
|
# It's stored in a different block
|
||||||
@ -859,55 +843,55 @@ def module_data(inp: ourlang.ModuleData) -> bytes:
|
|||||||
data_list.append(module_data_u32(constant.data_block.address))
|
data_list.append(module_data_u32(constant.data_block.address))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.u8:
|
if constant.type3 == prelude.u8:
|
||||||
assert isinstance(constant, ourlang.ConstantPrimitive)
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_u8(constant.value))
|
data_list.append(module_data_u8(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.u32:
|
if constant.type3 == prelude.u32:
|
||||||
assert isinstance(constant, ourlang.ConstantPrimitive)
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_u32(constant.value))
|
data_list.append(module_data_u32(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.u64:
|
if constant.type3 == prelude.u64:
|
||||||
assert isinstance(constant, ourlang.ConstantPrimitive)
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_u64(constant.value))
|
data_list.append(module_data_u64(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.i8:
|
if constant.type3 == prelude.i8:
|
||||||
assert isinstance(constant, ourlang.ConstantPrimitive)
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_i8(constant.value))
|
data_list.append(module_data_i8(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.i32:
|
if constant.type3 == prelude.i32:
|
||||||
assert isinstance(constant, ourlang.ConstantPrimitive)
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_i32(constant.value))
|
data_list.append(module_data_i32(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.i64:
|
if constant.type3 == prelude.i64:
|
||||||
assert isinstance(constant, ourlang.ConstantPrimitive)
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_i64(constant.value))
|
data_list.append(module_data_i64(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.f32:
|
if constant.type3 == prelude.f32:
|
||||||
assert isinstance(constant, ourlang.ConstantPrimitive)
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, float)
|
assert isinstance(constant.value, float)
|
||||||
data_list.append(module_data_f32(constant.value))
|
data_list.append(module_data_f32(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.f64:
|
if constant.type3 == prelude.f64:
|
||||||
assert isinstance(constant, ourlang.ConstantPrimitive)
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, float)
|
assert isinstance(constant.value, float)
|
||||||
data_list.append(module_data_f64(constant.value))
|
data_list.append(module_data_f64(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.bytes_:
|
if constant.type3 == prelude.bytes_:
|
||||||
assert isinstance(constant, ourlang.ConstantBytes)
|
assert isinstance(constant, ourlang.ConstantBytes)
|
||||||
assert isinstance(constant.value, bytes)
|
assert isinstance(constant.value, bytes)
|
||||||
data_list.append(module_data_u32(len(constant.value)))
|
data_list.append(module_data_u32(len(constant.value)))
|
||||||
@ -978,6 +962,9 @@ def module(inp: ourlang.Module) -> wasm.Module:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstructor) -> None:
|
def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstructor) -> None:
|
||||||
|
st_args = prelude.struct.did_construct(inp.struct_type3)
|
||||||
|
assert st_args is not None
|
||||||
|
|
||||||
tmp_var = wgn.temp_var_i32('struct_adr')
|
tmp_var = wgn.temp_var_i32('struct_adr')
|
||||||
|
|
||||||
# Allocated the required amounts of bytes in memory
|
# Allocated the required amounts of bytes in memory
|
||||||
@ -986,11 +973,9 @@ def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstruc
|
|||||||
wgn.local.set(tmp_var)
|
wgn.local.set(tmp_var)
|
||||||
|
|
||||||
# Store each member individually
|
# Store each member individually
|
||||||
for memname, mtyp3 in inp.struct_type3.members.items():
|
for memname, mtyp3 in st_args.items():
|
||||||
mtyp: Optional[str]
|
mtyp: Optional[str]
|
||||||
if type3classes.InternalPassAsPointer in mtyp3.classes:
|
if prelude.InternalPassAsPointer in mtyp3.classes:
|
||||||
mtyp = 'i32'
|
|
||||||
elif isinstance(mtyp3, type3types.StructType3):
|
|
||||||
mtyp = 'i32'
|
mtyp = 'i32'
|
||||||
else:
|
else:
|
||||||
mtyp = LOAD_STORE_TYPE_MAP.get(mtyp3.name)
|
mtyp = LOAD_STORE_TYPE_MAP.get(mtyp3.name)
|
||||||
@ -1001,7 +986,7 @@ def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstruc
|
|||||||
wgn.local.get(tmp_var)
|
wgn.local.get(tmp_var)
|
||||||
wgn.add_statement('local.get', f'${memname}')
|
wgn.add_statement('local.get', f'${memname}')
|
||||||
wgn.add_statement(f'{mtyp}.store', 'offset=' + str(calculate_member_offset(
|
wgn.add_statement(f'{mtyp}.store', 'offset=' + str(calculate_member_offset(
|
||||||
inp.struct_type3, memname
|
inp.struct_type3.name, st_args, memname
|
||||||
)))
|
)))
|
||||||
|
|
||||||
# Return the allocated address
|
# Return the allocated address
|
||||||
|
|||||||
@ -6,9 +6,10 @@ from typing import Dict, Iterable, List, Optional, Union
|
|||||||
|
|
||||||
from typing_extensions import Final
|
from typing_extensions import Final
|
||||||
|
|
||||||
|
from . import prelude
|
||||||
from .type3 import typeclasses as type3typeclasses
|
from .type3 import typeclasses as type3typeclasses
|
||||||
from .type3 import types as type3types
|
from .type3.placeholders import PlaceholderForType, Type3OrPlaceholder
|
||||||
from .type3.types import PlaceholderForType, StructType3, Type3, Type3OrPlaceholder
|
from .type3.types import Type3
|
||||||
|
|
||||||
WEBASSEMBLY_BUILTIN_BYTES_OPS: Final = ('len', )
|
WEBASSEMBLY_BUILTIN_BYTES_OPS: Final = ('len', )
|
||||||
|
|
||||||
@ -214,10 +215,10 @@ class AccessStructMember(Expression):
|
|||||||
__slots__ = ('varref', 'struct_type3', 'member', )
|
__slots__ = ('varref', 'struct_type3', 'member', )
|
||||||
|
|
||||||
varref: VariableReference
|
varref: VariableReference
|
||||||
struct_type3: StructType3
|
struct_type3: Type3OrPlaceholder
|
||||||
member: str
|
member: str
|
||||||
|
|
||||||
def __init__(self, varref: VariableReference, struct_type3: StructType3, member: str) -> None:
|
def __init__(self, varref: VariableReference, struct_type3: Type3OrPlaceholder, member: str) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.varref = varref
|
self.varref = varref
|
||||||
@ -326,7 +327,7 @@ class Function:
|
|||||||
self.exported = False
|
self.exported = False
|
||||||
self.imported = None
|
self.imported = None
|
||||||
self.statements = []
|
self.statements = []
|
||||||
self.returns_type3 = type3types.none # FIXME: This could be a placeholder
|
self.returns_type3 = prelude.none # FIXME: This could be a placeholder
|
||||||
self.posonlyargs = []
|
self.posonlyargs = []
|
||||||
|
|
||||||
class StructDefinition:
|
class StructDefinition:
|
||||||
@ -335,10 +336,10 @@ class StructDefinition:
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('struct_type3', 'lineno', )
|
__slots__ = ('struct_type3', 'lineno', )
|
||||||
|
|
||||||
struct_type3: StructType3
|
struct_type3: Type3
|
||||||
lineno: int
|
lineno: int
|
||||||
|
|
||||||
def __init__(self, struct_type3: StructType3, lineno: int) -> None:
|
def __init__(self, struct_type3: Type3, lineno: int) -> None:
|
||||||
self.struct_type3 = struct_type3
|
self.struct_type3 = struct_type3
|
||||||
self.lineno = lineno
|
self.lineno = lineno
|
||||||
|
|
||||||
@ -351,14 +352,16 @@ class StructConstructor(Function):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('struct_type3', )
|
__slots__ = ('struct_type3', )
|
||||||
|
|
||||||
struct_type3: StructType3
|
struct_type3: Type3
|
||||||
|
|
||||||
def __init__(self, struct_type3: StructType3) -> None:
|
def __init__(self, struct_type3: Type3) -> None:
|
||||||
super().__init__(f'@{struct_type3.name}@__init___@', -1)
|
super().__init__(f'@{struct_type3.name}@__init___@', -1)
|
||||||
|
|
||||||
self.returns_type3 = struct_type3
|
self.returns_type3 = struct_type3
|
||||||
|
|
||||||
for mem, typ in struct_type3.members.items():
|
st_args = prelude.struct.did_construct(struct_type3)
|
||||||
|
assert st_args is not None
|
||||||
|
for mem, typ in st_args.items():
|
||||||
self.posonlyargs.append(FunctionParam(mem, typ, ))
|
self.posonlyargs.append(FunctionParam(mem, typ, ))
|
||||||
|
|
||||||
self.struct_type3 = struct_type3
|
self.struct_type3 = struct_type3
|
||||||
|
|||||||
@ -4,6 +4,7 @@ Parses the source code from the plain text into a syntax tree
|
|||||||
import ast
|
import ast
|
||||||
from typing import Any, Dict, NoReturn, Union
|
from typing import Any, Dict, NoReturn, Union
|
||||||
|
|
||||||
|
from . import prelude
|
||||||
from .exceptions import StaticError
|
from .exceptions import StaticError
|
||||||
from .ourlang import (
|
from .ourlang import (
|
||||||
AccessStructMember,
|
AccessStructMember,
|
||||||
@ -31,29 +32,10 @@ from .ourlang import (
|
|||||||
UnaryOp,
|
UnaryOp,
|
||||||
VariableReference,
|
VariableReference,
|
||||||
)
|
)
|
||||||
|
from .prelude import PRELUDE_METHODS, PRELUDE_OPERATORS, PRELUDE_TYPES
|
||||||
from .type3 import typeclasses as type3typeclasses
|
from .type3 import typeclasses as type3typeclasses
|
||||||
from .type3 import types as type3types
|
from .type3 import types as type3types
|
||||||
|
|
||||||
PRELUDE_OPERATORS = {
|
|
||||||
**type3typeclasses.Bits.operators,
|
|
||||||
**type3typeclasses.Eq.operators,
|
|
||||||
**type3typeclasses.Ord.operators,
|
|
||||||
**type3typeclasses.Fractional.operators,
|
|
||||||
**type3typeclasses.Integral.operators,
|
|
||||||
**type3typeclasses.IntNum.operators,
|
|
||||||
**type3typeclasses.NatNum.operators,
|
|
||||||
}
|
|
||||||
|
|
||||||
PRELUDE_METHODS = {
|
|
||||||
**type3typeclasses.Bits.methods,
|
|
||||||
**type3typeclasses.Eq.methods,
|
|
||||||
**type3typeclasses.Ord.methods,
|
|
||||||
**type3typeclasses.Floating.methods,
|
|
||||||
**type3typeclasses.Fractional.methods,
|
|
||||||
**type3typeclasses.Integral.methods,
|
|
||||||
**type3typeclasses.IntNum.methods,
|
|
||||||
**type3typeclasses.NatNum.methods,
|
|
||||||
}
|
|
||||||
|
|
||||||
def phasm_parse(source: str) -> Module:
|
def phasm_parse(source: str) -> Module:
|
||||||
"""
|
"""
|
||||||
@ -252,7 +234,7 @@ class OurVisitor:
|
|||||||
|
|
||||||
members[stmt.target.id] = self.visit_type(module, stmt.annotation)
|
members[stmt.target.id] = self.visit_type(module, stmt.annotation)
|
||||||
|
|
||||||
return StructDefinition(type3types.StructType3(node.name, members), node.lineno)
|
return StructDefinition(prelude.struct(node.name, members, set()), node.lineno)
|
||||||
|
|
||||||
def pre_visit_Module_AnnAssign(self, module: Module, node: ast.AnnAssign) -> ModuleConstantDef:
|
def pre_visit_Module_AnnAssign(self, module: Module, node: ast.AnnAssign) -> ModuleConstantDef:
|
||||||
if not isinstance(node.target, ast.Name):
|
if not isinstance(node.target, ast.Name):
|
||||||
@ -509,7 +491,7 @@ class OurVisitor:
|
|||||||
'cast',
|
'cast',
|
||||||
self.visit_Module_FunctionDef_expr(module, function, our_locals, node.args[0]),
|
self.visit_Module_FunctionDef_expr(module, function, our_locals, node.args[0]),
|
||||||
)
|
)
|
||||||
unary_op.type3 = type3types.u32
|
unary_op.type3 = prelude.u32
|
||||||
return unary_op
|
return unary_op
|
||||||
elif node.func.id == 'len':
|
elif node.func.id == 'len':
|
||||||
if 1 != len(node.args):
|
if 1 != len(node.args):
|
||||||
@ -570,9 +552,6 @@ class OurVisitor:
|
|||||||
if not isinstance(varref, VariableReference):
|
if not isinstance(varref, VariableReference):
|
||||||
_raise_static_error(node.value, 'Must refer to variable')
|
_raise_static_error(node.value, 'Must refer to variable')
|
||||||
|
|
||||||
if not isinstance(varref.variable.type3, type3types.StructType3):
|
|
||||||
_raise_static_error(node.value, 'Must refer to struct')
|
|
||||||
|
|
||||||
return AccessStructMember(
|
return AccessStructMember(
|
||||||
varref,
|
varref,
|
||||||
varref.variable.type3,
|
varref.variable.type3,
|
||||||
@ -664,10 +643,10 @@ class OurVisitor:
|
|||||||
|
|
||||||
raise NotImplementedError(f'{node.value} as constant')
|
raise NotImplementedError(f'{node.value} as constant')
|
||||||
|
|
||||||
def visit_type(self, module: Module, node: ast.expr) -> type3types.PrimitiveType3:
|
def visit_type(self, module: Module, node: ast.expr) -> type3types.Type3:
|
||||||
if isinstance(node, ast.Constant):
|
if isinstance(node, ast.Constant):
|
||||||
if node.value is None:
|
if node.value is None:
|
||||||
return type3types.none
|
return prelude.none
|
||||||
|
|
||||||
_raise_static_error(node, f'Unrecognized type {node.value}')
|
_raise_static_error(node, f'Unrecognized type {node.value}')
|
||||||
|
|
||||||
@ -675,8 +654,8 @@ class OurVisitor:
|
|||||||
if not isinstance(node.ctx, ast.Load):
|
if not isinstance(node.ctx, ast.Load):
|
||||||
_raise_static_error(node, 'Must be load context')
|
_raise_static_error(node, 'Must be load context')
|
||||||
|
|
||||||
if node.id in type3types.LOOKUP_TABLE:
|
if node.id in PRELUDE_TYPES:
|
||||||
return type3types.LOOKUP_TABLE[node.id]
|
return PRELUDE_TYPES[node.id]
|
||||||
|
|
||||||
if node.id in module.struct_definitions:
|
if node.id in module.struct_definitions:
|
||||||
return module.struct_definitions[node.id].struct_type3
|
return module.struct_definitions[node.id].struct_type3
|
||||||
@ -693,7 +672,7 @@ class OurVisitor:
|
|||||||
if not isinstance(node.ctx, ast.Load):
|
if not isinstance(node.ctx, ast.Load):
|
||||||
_raise_static_error(node, 'Must be load context')
|
_raise_static_error(node, 'Must be load context')
|
||||||
|
|
||||||
return type3types.static_array(
|
return prelude.static_array(
|
||||||
self.visit_type(module, node.value),
|
self.visit_type(module, node.value),
|
||||||
type3types.IntType3(node.slice.value),
|
type3types.IntType3(node.slice.value),
|
||||||
)
|
)
|
||||||
@ -702,7 +681,7 @@ class OurVisitor:
|
|||||||
if not isinstance(node.ctx, ast.Load):
|
if not isinstance(node.ctx, ast.Load):
|
||||||
_raise_static_error(node, 'Must be load context')
|
_raise_static_error(node, 'Must be load context')
|
||||||
|
|
||||||
return type3types.tuple_(
|
return prelude.tuple_(
|
||||||
*(self.visit_type(module, elt) for elt in node.elts)
|
*(self.visit_type(module, elt) for elt in node.elts)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
274
phasm/prelude/__init__.py
Normal file
274
phasm/prelude/__init__.py
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
"""
|
||||||
|
The prelude are all the builtin types, type classes and methods
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ..type3.typeclasses import Type3Class, TypeVariable, instance_type_class
|
||||||
|
from ..type3.types import (
|
||||||
|
Type3,
|
||||||
|
TypeConstructor_StaticArray,
|
||||||
|
TypeConstructor_Struct,
|
||||||
|
TypeConstructor_Tuple,
|
||||||
|
)
|
||||||
|
|
||||||
|
none = Type3('none', [])
|
||||||
|
"""
|
||||||
|
The none type, for when functions simply don't return anything. e.g., IO().
|
||||||
|
"""
|
||||||
|
|
||||||
|
bool_ = Type3('bool', [])
|
||||||
|
"""
|
||||||
|
The bool type, either True or False
|
||||||
|
|
||||||
|
Suffixes with an underscores, as it's a Python builtin
|
||||||
|
"""
|
||||||
|
|
||||||
|
u8 = Type3('u8', [])
|
||||||
|
"""
|
||||||
|
The unsigned 8-bit integer type.
|
||||||
|
|
||||||
|
Operations on variables employ modular arithmetic, with modulus 2^8.
|
||||||
|
"""
|
||||||
|
|
||||||
|
u32 = Type3('u32', [])
|
||||||
|
"""
|
||||||
|
The unsigned 32-bit integer type.
|
||||||
|
|
||||||
|
Operations on variables employ modular arithmetic, with modulus 2^32.
|
||||||
|
"""
|
||||||
|
|
||||||
|
u64 = Type3('u64', [])
|
||||||
|
"""
|
||||||
|
The unsigned 64-bit integer type.
|
||||||
|
|
||||||
|
Operations on variables employ modular arithmetic, with modulus 2^64.
|
||||||
|
"""
|
||||||
|
|
||||||
|
i8 = Type3('i8', [])
|
||||||
|
"""
|
||||||
|
The signed 8-bit integer type.
|
||||||
|
|
||||||
|
Operations on variables employ modular arithmetic, with modulus 2^8, but
|
||||||
|
with the middel point being 0.
|
||||||
|
"""
|
||||||
|
|
||||||
|
i32 = Type3('i32', [])
|
||||||
|
"""
|
||||||
|
The unsigned 32-bit integer type.
|
||||||
|
|
||||||
|
Operations on variables employ modular arithmetic, with modulus 2^32, but
|
||||||
|
with the middel point being 0.
|
||||||
|
"""
|
||||||
|
|
||||||
|
i64 = Type3('i64', [])
|
||||||
|
"""
|
||||||
|
The unsigned 64-bit integer type.
|
||||||
|
|
||||||
|
Operations on variables employ modular arithmetic, with modulus 2^64, but
|
||||||
|
with the middel point being 0.
|
||||||
|
"""
|
||||||
|
|
||||||
|
f32 = Type3('f32', [])
|
||||||
|
"""
|
||||||
|
A 32-bits IEEE 754 float, of 32 bits width.
|
||||||
|
"""
|
||||||
|
|
||||||
|
f64 = Type3('f64', [])
|
||||||
|
"""
|
||||||
|
A 32-bits IEEE 754 float, of 64 bits width.
|
||||||
|
"""
|
||||||
|
|
||||||
|
bytes_ = Type3('bytes', [])
|
||||||
|
"""
|
||||||
|
This is a runtime-determined length piece of memory that can be indexed at runtime.
|
||||||
|
"""
|
||||||
|
|
||||||
|
static_array = TypeConstructor_StaticArray('static_array', [], [])
|
||||||
|
"""
|
||||||
|
A type constructor.
|
||||||
|
|
||||||
|
Any static array is a fixed length piece of memory that can be indexed at runtime.
|
||||||
|
|
||||||
|
It should be applied with one argument. It has a runtime-dynamic length
|
||||||
|
of the same type repeated.
|
||||||
|
"""
|
||||||
|
|
||||||
|
tuple_ = TypeConstructor_Tuple('tuple', [], [])
|
||||||
|
"""
|
||||||
|
This is a fixed length piece of memory.
|
||||||
|
|
||||||
|
It should be applied with zero or more arguments. It has a compile time
|
||||||
|
determined length, and each argument can be different.
|
||||||
|
"""
|
||||||
|
|
||||||
|
struct = TypeConstructor_Struct('struct', [], [])
|
||||||
|
"""
|
||||||
|
This is like a tuple, but each argument is named, so that developers
|
||||||
|
can get and set fields by name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
PRELUDE_TYPES: dict[str, Type3] = {
|
||||||
|
'none': none,
|
||||||
|
'bool': bool_,
|
||||||
|
'u8': u8,
|
||||||
|
'u32': u32,
|
||||||
|
'u64': u64,
|
||||||
|
'i8': i8,
|
||||||
|
'i32': i32,
|
||||||
|
'i64': i64,
|
||||||
|
'f32': f32,
|
||||||
|
'f64': f64,
|
||||||
|
'bytes': bytes_,
|
||||||
|
}
|
||||||
|
|
||||||
|
a = TypeVariable('a')
|
||||||
|
|
||||||
|
|
||||||
|
InternalPassAsPointer = Type3Class('InternalPassAsPointer', [a], methods={}, operators={})
|
||||||
|
"""
|
||||||
|
Internal type class to keep track which types we pass arounds as a pointer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
instance_type_class(InternalPassAsPointer, bytes_)
|
||||||
|
instance_type_class(InternalPassAsPointer, static_array)
|
||||||
|
instance_type_class(InternalPassAsPointer, tuple_)
|
||||||
|
instance_type_class(InternalPassAsPointer, struct)
|
||||||
|
|
||||||
|
Eq = Type3Class('Eq', [a], methods={}, operators={
|
||||||
|
'==': [a, a, bool_],
|
||||||
|
'!=': [a, a, bool_],
|
||||||
|
# FIXME: Do we want to expose 'eqz'? Or is that a compiler optimization?
|
||||||
|
})
|
||||||
|
|
||||||
|
instance_type_class(Eq, u8)
|
||||||
|
instance_type_class(Eq, u32)
|
||||||
|
instance_type_class(Eq, u64)
|
||||||
|
instance_type_class(Eq, i8)
|
||||||
|
instance_type_class(Eq, i32)
|
||||||
|
instance_type_class(Eq, i64)
|
||||||
|
instance_type_class(Eq, f32)
|
||||||
|
instance_type_class(Eq, f64)
|
||||||
|
instance_type_class(Eq, static_array)
|
||||||
|
|
||||||
|
Ord = Type3Class('Ord', [a], methods={
|
||||||
|
'min': [a, a, a],
|
||||||
|
'max': [a, a, a],
|
||||||
|
}, operators={
|
||||||
|
'<': [a, a, bool_],
|
||||||
|
'<=': [a, a, bool_],
|
||||||
|
'>': [a, a, bool_],
|
||||||
|
'>=': [a, a, bool_],
|
||||||
|
}, inherited_classes=[Eq])
|
||||||
|
|
||||||
|
instance_type_class(Ord, u8)
|
||||||
|
instance_type_class(Ord, u32)
|
||||||
|
instance_type_class(Ord, u64)
|
||||||
|
instance_type_class(Ord, i8)
|
||||||
|
instance_type_class(Ord, i32)
|
||||||
|
instance_type_class(Ord, i64)
|
||||||
|
instance_type_class(Ord, f32)
|
||||||
|
instance_type_class(Ord, f64)
|
||||||
|
|
||||||
|
Bits = Type3Class('Bits', [a], methods={
|
||||||
|
'shl': [a, u32, a], # Logical shift left
|
||||||
|
'shr': [a, u32, a], # Logical shift right
|
||||||
|
'rotl': [a, u32, a], # Rotate bits left
|
||||||
|
'rotr': [a, u32, a], # Rotate bits right
|
||||||
|
# FIXME: Do we want to expose clz, ctz, popcnt?
|
||||||
|
}, operators={
|
||||||
|
'&': [a, a, a], # Bit-wise and
|
||||||
|
'|': [a, a, a], # Bit-wise or
|
||||||
|
'^': [a, a, a], # Bit-wise xor
|
||||||
|
})
|
||||||
|
|
||||||
|
instance_type_class(Bits, u8)
|
||||||
|
instance_type_class(Bits, u32)
|
||||||
|
instance_type_class(Bits, u64)
|
||||||
|
|
||||||
|
NatNum = Type3Class('NatNum', [a], methods={}, operators={
|
||||||
|
'+': [a, a, a],
|
||||||
|
'-': [a, a, a],
|
||||||
|
'*': [a, a, a],
|
||||||
|
'<<': [a, u32, a], # Arithmic shift left
|
||||||
|
'>>': [a, u32, a], # Arithmic shift right
|
||||||
|
})
|
||||||
|
|
||||||
|
instance_type_class(NatNum, u32)
|
||||||
|
instance_type_class(NatNum, u64)
|
||||||
|
instance_type_class(NatNum, i32)
|
||||||
|
instance_type_class(NatNum, i64)
|
||||||
|
instance_type_class(NatNum, f32)
|
||||||
|
instance_type_class(NatNum, f64)
|
||||||
|
|
||||||
|
IntNum = Type3Class('IntNum', [a], methods={
|
||||||
|
'abs': [a, a],
|
||||||
|
'neg': [a, a],
|
||||||
|
}, operators={}, inherited_classes=[NatNum])
|
||||||
|
|
||||||
|
instance_type_class(IntNum, i32)
|
||||||
|
instance_type_class(IntNum, i64)
|
||||||
|
instance_type_class(IntNum, f32)
|
||||||
|
instance_type_class(IntNum, f64)
|
||||||
|
|
||||||
|
Integral = Type3Class('Eq', [a], methods={
|
||||||
|
}, operators={
|
||||||
|
'//': [a, a, a],
|
||||||
|
'%': [a, a, a],
|
||||||
|
}, inherited_classes=[NatNum])
|
||||||
|
|
||||||
|
instance_type_class(Integral, u32)
|
||||||
|
instance_type_class(Integral, u64)
|
||||||
|
instance_type_class(Integral, i32)
|
||||||
|
instance_type_class(Integral, i64)
|
||||||
|
|
||||||
|
Fractional = Type3Class('Fractional', [a], methods={
|
||||||
|
'ceil': [a, a],
|
||||||
|
'floor': [a, a],
|
||||||
|
'trunc': [a, a],
|
||||||
|
'nearest': [a, a],
|
||||||
|
}, operators={
|
||||||
|
'/': [a, a, a],
|
||||||
|
}, inherited_classes=[NatNum])
|
||||||
|
|
||||||
|
instance_type_class(Fractional, f32)
|
||||||
|
instance_type_class(Fractional, f64)
|
||||||
|
|
||||||
|
Floating = Type3Class('Floating', [a], methods={
|
||||||
|
'sqrt': [a, a],
|
||||||
|
}, operators={}, inherited_classes=[Fractional])
|
||||||
|
|
||||||
|
# FIXME: Do we want to expose copysign?
|
||||||
|
|
||||||
|
instance_type_class(Floating, f32)
|
||||||
|
instance_type_class(Floating, f64)
|
||||||
|
|
||||||
|
PRELUDE_TYPE_CLASSES = {
|
||||||
|
'Eq': Eq,
|
||||||
|
'Ord': Ord,
|
||||||
|
'Bits': Bits,
|
||||||
|
'NatNum': NatNum,
|
||||||
|
'IntNum': IntNum,
|
||||||
|
'Integral': Integral,
|
||||||
|
'Fractional': Fractional,
|
||||||
|
'Floating': Floating,
|
||||||
|
}
|
||||||
|
|
||||||
|
PRELUDE_OPERATORS = {
|
||||||
|
**Bits.operators,
|
||||||
|
**Eq.operators,
|
||||||
|
**Ord.operators,
|
||||||
|
**Fractional.operators,
|
||||||
|
**Integral.operators,
|
||||||
|
**IntNum.operators,
|
||||||
|
**NatNum.operators,
|
||||||
|
}
|
||||||
|
|
||||||
|
PRELUDE_METHODS = {
|
||||||
|
**Bits.methods,
|
||||||
|
**Eq.methods,
|
||||||
|
**Ord.methods,
|
||||||
|
**Floating.methods,
|
||||||
|
**Fractional.methods,
|
||||||
|
**Integral.methods,
|
||||||
|
**IntNum.methods,
|
||||||
|
**NatNum.methods,
|
||||||
|
}
|
||||||
@ -1,35 +1,35 @@
|
|||||||
|
from . import prelude
|
||||||
from .type3 import types as type3types
|
from .type3 import types as type3types
|
||||||
|
|
||||||
|
|
||||||
def calculate_alloc_size(typ: type3types.Type3, is_member: bool = False) -> int:
|
def calculate_alloc_size(typ: type3types.Type3, is_member: bool = False) -> int:
|
||||||
if typ in (type3types.u8, type3types.i8, ):
|
if typ in (prelude.u8, prelude.i8, ):
|
||||||
return 4 # FIXME: We allocate 4 bytes for every u8 since you load them into an i32
|
return 4 # FIXME: We allocate 4 bytes for every u8 since you load them into an i32
|
||||||
|
|
||||||
if typ in (type3types.u32, type3types.i32, type3types.f32, ):
|
if typ in (prelude.u32, prelude.i32, prelude.f32, ):
|
||||||
return 4
|
return 4
|
||||||
|
|
||||||
if typ in (type3types.u64, type3types.i64, type3types.f64, ):
|
if typ in (prelude.u64, prelude.i64, prelude.f64, ):
|
||||||
return 8
|
return 8
|
||||||
|
|
||||||
if typ == type3types.bytes_:
|
if typ == prelude.bytes_:
|
||||||
if is_member:
|
if is_member:
|
||||||
return 4
|
return 4
|
||||||
|
|
||||||
raise NotImplementedError # When does this happen?
|
raise NotImplementedError # When does this happen?
|
||||||
|
|
||||||
if isinstance(typ, type3types.StructType3):
|
st_args = prelude.struct.did_construct(typ)
|
||||||
|
if st_args is not None:
|
||||||
if is_member:
|
if is_member:
|
||||||
# Structs referred to by other structs or tuples are pointers
|
# Structs referred to by other structs or tuples are pointers
|
||||||
return 4
|
return 4
|
||||||
|
|
||||||
return sum(
|
return sum(
|
||||||
calculate_alloc_size(x, is_member=True)
|
calculate_alloc_size(x, is_member=True)
|
||||||
for x in typ.members.values()
|
for x in st_args.values()
|
||||||
)
|
)
|
||||||
|
|
||||||
assert isinstance(typ, type3types.PrimitiveType3)
|
sa_args = prelude.static_array.did_construct(typ)
|
||||||
|
|
||||||
sa_args = type3types.static_array.did_construct(typ)
|
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
if is_member:
|
if is_member:
|
||||||
# tuples referred to by other structs or tuples are pointers
|
# tuples referred to by other structs or tuples are pointers
|
||||||
@ -39,7 +39,7 @@ def calculate_alloc_size(typ: type3types.Type3, is_member: bool = False) -> int:
|
|||||||
|
|
||||||
return sa_len.value * calculate_alloc_size(sa_type, is_member=True)
|
return sa_len.value * calculate_alloc_size(sa_type, is_member=True)
|
||||||
|
|
||||||
tp_args = type3types.tuple_.did_construct(typ)
|
tp_args = prelude.tuple_.did_construct(typ)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
if is_member:
|
if is_member:
|
||||||
# tuples referred to by other structs or tuples are pointers
|
# tuples referred to by other structs or tuples are pointers
|
||||||
@ -47,25 +47,19 @@ def calculate_alloc_size(typ: type3types.Type3, is_member: bool = False) -> int:
|
|||||||
|
|
||||||
size = 0
|
size = 0
|
||||||
for arg in tp_args:
|
for arg in tp_args:
|
||||||
assert not isinstance(arg, type3types.IntType3)
|
|
||||||
|
|
||||||
if isinstance(arg, type3types.PlaceholderForType):
|
|
||||||
assert isinstance(arg.resolve_as, type3types.PrimitiveType3)
|
|
||||||
arg = arg.resolve_as
|
|
||||||
|
|
||||||
size += calculate_alloc_size(arg, is_member=True)
|
size += calculate_alloc_size(arg, is_member=True)
|
||||||
|
|
||||||
return size
|
return size
|
||||||
|
|
||||||
raise NotImplementedError(calculate_alloc_size, typ)
|
raise NotImplementedError(calculate_alloc_size, typ)
|
||||||
|
|
||||||
def calculate_member_offset(struct_type3: type3types.StructType3, member: str) -> int:
|
def calculate_member_offset(st_name: str, st_args: dict[str, type3types.Type3], needle: str) -> int:
|
||||||
result = 0
|
result = 0
|
||||||
|
|
||||||
for mem, memtyp in struct_type3.members.items():
|
for memnam, memtyp in st_args.items():
|
||||||
if member == mem:
|
if needle == memnam:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
result += calculate_alloc_size(memtyp, is_member=True)
|
result += calculate_alloc_size(memtyp, is_member=True)
|
||||||
|
|
||||||
raise Exception(f'{member} not in {struct_type3}')
|
raise Exception(f'{needle} not in {st_name}')
|
||||||
|
|||||||
@ -5,8 +5,8 @@ These need to be resolved before the program can be compiled.
|
|||||||
"""
|
"""
|
||||||
from typing import Dict, List, Optional, Tuple, Union
|
from typing import Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from .. import ourlang
|
from .. import ourlang, prelude
|
||||||
from . import typeclasses, types
|
from . import placeholders, typeclasses, types
|
||||||
|
|
||||||
|
|
||||||
class Error:
|
class Error:
|
||||||
@ -32,13 +32,13 @@ class RequireTypeSubstitutes:
|
|||||||
typing of the program, so this constraint can be updated.
|
typing of the program, so this constraint can be updated.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SubstitutionMap = Dict[types.PlaceholderForType, types.Type3]
|
SubstitutionMap = Dict[placeholders.PlaceholderForType, types.Type3]
|
||||||
|
|
||||||
NewConstraintList = List['ConstraintBase']
|
NewConstraintList = List['ConstraintBase']
|
||||||
|
|
||||||
CheckResult = Union[None, SubstitutionMap, Error, NewConstraintList, RequireTypeSubstitutes]
|
CheckResult = Union[None, SubstitutionMap, Error, NewConstraintList, RequireTypeSubstitutes]
|
||||||
|
|
||||||
HumanReadableRet = Tuple[str, Dict[str, Union[str, ourlang.Expression, types.Type3, types.PlaceholderForType]]]
|
HumanReadableRet = Tuple[str, Dict[str, Union[str, ourlang.Expression, types.Type3, placeholders.PlaceholderForType]]]
|
||||||
|
|
||||||
class Context:
|
class Context:
|
||||||
"""
|
"""
|
||||||
@ -92,9 +92,9 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('type_list', )
|
__slots__ = ('type_list', )
|
||||||
|
|
||||||
type_list: List[types.Type3OrPlaceholder]
|
type_list: List[placeholders.Type3OrPlaceholder]
|
||||||
|
|
||||||
def __init__(self, *type_list: types.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
def __init__(self, *type_list: placeholders.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
assert len(type_list) > 1
|
assert len(type_list) > 1
|
||||||
@ -102,21 +102,17 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
known_types: List[types.Type3] = []
|
known_types: List[types.Type3] = []
|
||||||
placeholders = []
|
phft_list = []
|
||||||
for typ in self.type_list:
|
for typ in self.type_list:
|
||||||
if isinstance(typ, types.IntType3):
|
if isinstance(typ, types.Type3):
|
||||||
known_types.append(typ)
|
known_types.append(typ)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(typ, (types.PrimitiveType3, types.StructType3, )):
|
if isinstance(typ, placeholders.PlaceholderForType):
|
||||||
known_types.append(typ)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(typ, types.PlaceholderForType):
|
|
||||||
if typ.resolve_as is not None:
|
if typ.resolve_as is not None:
|
||||||
known_types.append(typ.resolve_as)
|
known_types.append(typ.resolve_as)
|
||||||
else:
|
else:
|
||||||
placeholders.append(typ)
|
phft_list.append(typ)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
raise NotImplementedError(typ)
|
raise NotImplementedError(typ)
|
||||||
@ -124,28 +120,20 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
if not known_types:
|
if not known_types:
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
new_constraint_list: List[ConstraintBase] = []
|
|
||||||
|
|
||||||
first_type = known_types[0]
|
first_type = known_types[0]
|
||||||
for typ in known_types[1:]:
|
for ktyp in known_types[1:]:
|
||||||
if typ != first_type:
|
if ktyp != first_type:
|
||||||
return Error(f'{typ:s} must be {first_type:s} instead', comment=self.comment)
|
return Error(f'{typ:s} must be {first_type:s} instead', comment=self.comment)
|
||||||
|
|
||||||
if new_constraint_list:
|
|
||||||
# If this happens, make CheckResult a class that can have both
|
|
||||||
assert not placeholders, 'Cannot (yet) return both new placeholders and new constraints'
|
|
||||||
|
|
||||||
return new_constraint_list
|
|
||||||
|
|
||||||
if not placeholders:
|
if not placeholders:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for typ in placeholders:
|
for phft in phft_list:
|
||||||
typ.resolve_as = first_type
|
phft.resolve_as = first_type
|
||||||
|
|
||||||
return {
|
return {
|
||||||
typ: first_type
|
typ: first_type
|
||||||
for typ in placeholders
|
for typ in phft_list
|
||||||
}
|
}
|
||||||
|
|
||||||
def human_readable(self) -> HumanReadableRet:
|
def human_readable(self) -> HumanReadableRet:
|
||||||
@ -163,7 +151,7 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
||||||
|
|
||||||
class TupleMatchConstraint(ConstraintBase):
|
class TupleMatchConstraint(ConstraintBase):
|
||||||
def __init__(self, exp_type: types.Type3OrPlaceholder, args: List[types.Type3OrPlaceholder], comment: str):
|
def __init__(self, exp_type: placeholders.Type3OrPlaceholder, args: List[placeholders.Type3OrPlaceholder], comment: str):
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.exp_type = exp_type
|
self.exp_type = exp_type
|
||||||
@ -171,15 +159,15 @@ class TupleMatchConstraint(ConstraintBase):
|
|||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
exp_type = self.exp_type
|
exp_type = self.exp_type
|
||||||
if isinstance(exp_type, types.PlaceholderForType):
|
if isinstance(exp_type, placeholders.PlaceholderForType):
|
||||||
if exp_type.resolve_as is None:
|
if exp_type.resolve_as is None:
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
exp_type = exp_type.resolve_as
|
exp_type = exp_type.resolve_as
|
||||||
|
|
||||||
assert isinstance(exp_type, types.PrimitiveType3)
|
assert isinstance(exp_type, types.Type3)
|
||||||
|
|
||||||
sa_args = types.static_array.did_construct(exp_type)
|
sa_args = prelude.static_array.did_construct(exp_type)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
|
|
||||||
@ -191,7 +179,7 @@ class TupleMatchConstraint(ConstraintBase):
|
|||||||
for arg in self.args
|
for arg in self.args
|
||||||
]
|
]
|
||||||
|
|
||||||
tp_args = types.tuple_.did_construct(exp_type)
|
tp_args = prelude.tuple_.did_construct(exp_type)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
if len(tp_args) != len(self.args):
|
if len(tp_args) != len(self.args):
|
||||||
return Error('Mismatch between applied types argument count', comment=self.comment)
|
return Error('Mismatch between applied types argument count', comment=self.comment)
|
||||||
@ -209,10 +197,10 @@ class CastableConstraint(ConstraintBase):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('from_type3', 'to_type3', )
|
__slots__ = ('from_type3', 'to_type3', )
|
||||||
|
|
||||||
from_type3: types.Type3OrPlaceholder
|
from_type3: placeholders.Type3OrPlaceholder
|
||||||
to_type3: types.Type3OrPlaceholder
|
to_type3: placeholders.Type3OrPlaceholder
|
||||||
|
|
||||||
def __init__(self, from_type3: types.Type3OrPlaceholder, to_type3: types.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
def __init__(self, from_type3: placeholders.Type3OrPlaceholder, to_type3: placeholders.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.from_type3 = from_type3
|
self.from_type3 = from_type3
|
||||||
@ -220,17 +208,17 @@ class CastableConstraint(ConstraintBase):
|
|||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
ftyp = self.from_type3
|
ftyp = self.from_type3
|
||||||
if isinstance(ftyp, types.PlaceholderForType) and ftyp.resolve_as is not None:
|
if isinstance(ftyp, placeholders.PlaceholderForType) and ftyp.resolve_as is not None:
|
||||||
ftyp = ftyp.resolve_as
|
ftyp = ftyp.resolve_as
|
||||||
|
|
||||||
ttyp = self.to_type3
|
ttyp = self.to_type3
|
||||||
if isinstance(ttyp, types.PlaceholderForType) and ttyp.resolve_as is not None:
|
if isinstance(ttyp, placeholders.PlaceholderForType) and ttyp.resolve_as is not None:
|
||||||
ttyp = ttyp.resolve_as
|
ttyp = ttyp.resolve_as
|
||||||
|
|
||||||
if isinstance(ftyp, types.PlaceholderForType) or isinstance(ttyp, types.PlaceholderForType):
|
if isinstance(ftyp, placeholders.PlaceholderForType) or isinstance(ttyp, placeholders.PlaceholderForType):
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
if ftyp is types.u8 and ttyp is types.u32:
|
if ftyp is prelude.u8 and ttyp is prelude.u32:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return Error(f'Cannot cast {ftyp.name} to {ttyp.name}')
|
return Error(f'Cannot cast {ftyp.name} to {ttyp.name}')
|
||||||
@ -254,13 +242,13 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
__slots__ = ('type_class3', 'type3', )
|
__slots__ = ('type_class3', 'type3', )
|
||||||
|
|
||||||
type_class3: Union[str, typeclasses.Type3Class]
|
type_class3: Union[str, typeclasses.Type3Class]
|
||||||
type3: types.Type3OrPlaceholder
|
type3: placeholders.Type3OrPlaceholder
|
||||||
|
|
||||||
DATA = {
|
DATA = {
|
||||||
'bytes': {'Foldable', 'Sized'},
|
'bytes': {'Foldable', 'Sized'},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, type_class3: Union[str, typeclasses.Type3Class], type3: types.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
def __init__(self, type_class3: Union[str, typeclasses.Type3Class], type3: placeholders.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.type_class3 = type_class3
|
self.type_class3 = type_class3
|
||||||
@ -268,10 +256,10 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
typ = self.type3
|
typ = self.type3
|
||||||
if isinstance(typ, types.PlaceholderForType) and typ.resolve_as is not None:
|
if isinstance(typ, placeholders.PlaceholderForType) and typ.resolve_as is not None:
|
||||||
typ = typ.resolve_as
|
typ = typ.resolve_as
|
||||||
|
|
||||||
if isinstance(typ, types.PlaceholderForType):
|
if isinstance(typ, placeholders.PlaceholderForType):
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
if isinstance(self.type_class3, typeclasses.Type3Class):
|
if isinstance(self.type_class3, typeclasses.Type3Class):
|
||||||
@ -301,12 +289,12 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('type3', 'literal', )
|
__slots__ = ('type3', 'literal', )
|
||||||
|
|
||||||
type3: types.Type3OrPlaceholder
|
type3: placeholders.Type3OrPlaceholder
|
||||||
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct]
|
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
type3: types.Type3OrPlaceholder,
|
type3: placeholders.Type3OrPlaceholder,
|
||||||
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct],
|
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct],
|
||||||
comment: Optional[str] = None,
|
comment: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -330,7 +318,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
'f64': None,
|
'f64': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if isinstance(self.type3, types.PlaceholderForType):
|
if isinstance(self.type3, placeholders.PlaceholderForType):
|
||||||
if self.type3.resolve_as is None:
|
if self.type3.resolve_as is None:
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
@ -359,7 +347,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
|
|
||||||
return Error('Must be real', comment=self.comment) # FIXME: Add line information
|
return Error('Must be real', comment=self.comment) # FIXME: Add line information
|
||||||
|
|
||||||
if self.type3 is types.bytes_:
|
if self.type3 is prelude.bytes_:
|
||||||
if isinstance(self.literal.value, bytes):
|
if isinstance(self.literal.value, bytes):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -367,9 +355,9 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
|
|
||||||
res: NewConstraintList
|
res: NewConstraintList
|
||||||
|
|
||||||
assert isinstance(self.type3, types.PrimitiveType3)
|
assert isinstance(self.type3, types.Type3)
|
||||||
|
|
||||||
tp_args = types.tuple_.did_construct(self.type3)
|
tp_args = prelude.tuple_.did_construct(self.type3)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
if not isinstance(self.literal, ourlang.ConstantTuple):
|
if not isinstance(self.literal, ourlang.ConstantTuple):
|
||||||
return Error('Must be tuple', comment=self.comment)
|
return Error('Must be tuple', comment=self.comment)
|
||||||
@ -390,7 +378,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
sa_args = types.static_array.did_construct(self.type3)
|
sa_args = prelude.static_array.did_construct(self.type3)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
if not isinstance(self.literal, ourlang.ConstantTuple):
|
if not isinstance(self.literal, ourlang.ConstantTuple):
|
||||||
return Error('Must be tuple', comment=self.comment)
|
return Error('Must be tuple', comment=self.comment)
|
||||||
@ -413,7 +401,8 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
if isinstance(self.type3, types.StructType3):
|
st_args = prelude.struct.did_construct(self.type3)
|
||||||
|
if st_args is not None:
|
||||||
if not isinstance(self.literal, ourlang.ConstantStruct):
|
if not isinstance(self.literal, ourlang.ConstantStruct):
|
||||||
return Error('Must be struct')
|
return Error('Must be struct')
|
||||||
|
|
||||||
@ -421,18 +410,18 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
return Error('Struct mismatch')
|
return Error('Struct mismatch')
|
||||||
|
|
||||||
|
|
||||||
if len(self.type3.members) != len(self.literal.value):
|
if len(st_args) != len(self.literal.value):
|
||||||
return Error('Struct element count mismatch')
|
return Error('Struct element count mismatch')
|
||||||
|
|
||||||
res = []
|
res = []
|
||||||
|
|
||||||
res.extend(
|
res.extend(
|
||||||
LiteralFitsConstraint(x, y)
|
LiteralFitsConstraint(x, y)
|
||||||
for x, y in zip(self.type3.members.values(), self.literal.value)
|
for x, y in zip(st_args.values(), self.literal.value)
|
||||||
)
|
)
|
||||||
res.extend(
|
res.extend(
|
||||||
SameTypeConstraint(x_t, y.type3, comment=f'{self.literal.struct_name}.{x_n}')
|
SameTypeConstraint(x_t, y.type3, comment=f'{self.literal.struct_name}.{x_n}')
|
||||||
for (x_n, x_t, ), y in zip(self.type3.members.items(), self.literal.value)
|
for (x_n, x_t, ), y in zip(st_args.items(), self.literal.value)
|
||||||
)
|
)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
@ -457,12 +446,12 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('ret_type3', 'type3', 'index', 'index_type3', )
|
__slots__ = ('ret_type3', 'type3', 'index', 'index_type3', )
|
||||||
|
|
||||||
ret_type3: types.Type3OrPlaceholder
|
ret_type3: placeholders.Type3OrPlaceholder
|
||||||
type3: types.Type3OrPlaceholder
|
type3: placeholders.Type3OrPlaceholder
|
||||||
index: ourlang.Expression
|
index: ourlang.Expression
|
||||||
index_type3: types.Type3OrPlaceholder
|
index_type3: placeholders.Type3OrPlaceholder
|
||||||
|
|
||||||
def __init__(self, ret_type3: types.Type3OrPlaceholder, type3: types.Type3OrPlaceholder, index: ourlang.Expression, comment: Optional[str] = None) -> None:
|
def __init__(self, ret_type3: placeholders.Type3OrPlaceholder, type3: placeholders.Type3OrPlaceholder, index: ourlang.Expression, comment: Optional[str] = None) -> None:
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.ret_type3 = ret_type3
|
self.ret_type3 = ret_type3
|
||||||
@ -472,20 +461,20 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
exp_type = self.type3
|
exp_type = self.type3
|
||||||
if isinstance(exp_type, types.PlaceholderForType):
|
if isinstance(exp_type, placeholders.PlaceholderForType):
|
||||||
if exp_type.resolve_as is None:
|
if exp_type.resolve_as is None:
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
exp_type = exp_type.resolve_as
|
exp_type = exp_type.resolve_as
|
||||||
|
|
||||||
assert isinstance(exp_type, types.PrimitiveType3)
|
assert isinstance(exp_type, types.Type3)
|
||||||
|
|
||||||
sa_args = types.static_array.did_construct(exp_type)
|
sa_args = prelude.static_array.did_construct(exp_type)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
|
|
||||||
result: List[ConstraintBase] = [
|
result: List[ConstraintBase] = [
|
||||||
SameTypeConstraint(types.u32, self.index_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||||
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -500,7 +489,7 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
# We special case tuples to allow for ease of use to the programmer
|
# We special case tuples to allow for ease of use to the programmer
|
||||||
# e.g. rather than having to do `fst a` and `snd a` and only have to-sized tuples
|
# e.g. rather than having to do `fst a` and `snd a` and only have to-sized tuples
|
||||||
# we use a[0] and a[1] and allow for a[2] and on.
|
# we use a[0] and a[1] and allow for a[2] and on.
|
||||||
tp_args = types.tuple_.did_construct(exp_type)
|
tp_args = prelude.tuple_.did_construct(exp_type)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
if not isinstance(self.index, ourlang.ConstantPrimitive):
|
if not isinstance(self.index, ourlang.ConstantPrimitive):
|
||||||
return Error('Must index with literal')
|
return Error('Must index with literal')
|
||||||
@ -512,14 +501,14 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
return Error('Tuple index out of range')
|
return Error('Tuple index out of range')
|
||||||
|
|
||||||
return [
|
return [
|
||||||
SameTypeConstraint(types.u32, self.index_type3, comment=f'Tuple subscript index {self.index.value}'),
|
SameTypeConstraint(prelude.u32, self.index_type3, comment=f'Tuple subscript index {self.index.value}'),
|
||||||
SameTypeConstraint(tp_args[self.index.value], self.ret_type3, comment=f'Tuple subscript index {self.index.value}'),
|
SameTypeConstraint(tp_args[self.index.value], self.ret_type3, comment=f'Tuple subscript index {self.index.value}'),
|
||||||
]
|
]
|
||||||
|
|
||||||
if exp_type is types.bytes_:
|
if exp_type is prelude.bytes_:
|
||||||
return [
|
return [
|
||||||
SameTypeConstraint(types.u32, self.index_type3, comment='([]) :: bytes -> u32 -> u8'),
|
SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: bytes -> u32 -> u8'),
|
||||||
SameTypeConstraint(types.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
|
SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
|
||||||
]
|
]
|
||||||
|
|
||||||
return Error(f'{exp_type.name} cannot be subscripted')
|
return Error(f'{exp_type.name} cannot be subscripted')
|
||||||
|
|||||||
@ -5,7 +5,8 @@ The constraints solver can then try to resolve all constraints.
|
|||||||
"""
|
"""
|
||||||
from typing import Generator, List
|
from typing import Generator, List
|
||||||
|
|
||||||
from .. import ourlang
|
from .. import ourlang, prelude
|
||||||
|
from . import placeholders as placeholders
|
||||||
from . import typeclasses as type3typeclasses
|
from . import typeclasses as type3typeclasses
|
||||||
from . import types as type3types
|
from . import types as type3types
|
||||||
from .constraints import (
|
from .constraints import (
|
||||||
@ -50,7 +51,7 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
if 'len' == inp.operator:
|
if 'len' == inp.operator:
|
||||||
yield from expression(ctx, inp.right)
|
yield from expression(ctx, inp.right)
|
||||||
yield MustImplementTypeClassConstraint('Sized', inp.right.type3)
|
yield MustImplementTypeClassConstraint('Sized', inp.right.type3)
|
||||||
yield SameTypeConstraint(type3types.u32, inp.type3, comment='len :: Sized a => a -> u32')
|
yield SameTypeConstraint(prelude.u32, inp.type3, comment='len :: Sized a => a -> u32')
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'cast' == inp.operator:
|
if 'cast' == inp.operator:
|
||||||
@ -62,7 +63,7 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
|
|
||||||
if isinstance(inp, ourlang.BinaryOp):
|
if isinstance(inp, ourlang.BinaryOp):
|
||||||
type_var_map = {
|
type_var_map = {
|
||||||
x: type3types.PlaceholderForType([])
|
x: placeholders.PlaceholderForType([])
|
||||||
for x in inp.operator.signature
|
for x in inp.operator.signature
|
||||||
if isinstance(x, type3typeclasses.TypeVariable)
|
if isinstance(x, type3typeclasses.TypeVariable)
|
||||||
}
|
}
|
||||||
@ -83,12 +84,11 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
yield SameTypeConstraint(type_var_map[sig_part], arg_expr.type3)
|
yield SameTypeConstraint(type_var_map[sig_part], arg_expr.type3)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(sig_part, type3typeclasses.TypeReference):
|
if isinstance(sig_part, type3types.Type3):
|
||||||
# On key error: We probably have to a lot of work to do refactoring
|
yield SameTypeConstraint(sig_part, arg_expr.type3)
|
||||||
# the type lookups
|
|
||||||
exp_type = type3types.LOOKUP_TABLE[sig_part.name]
|
|
||||||
yield SameTypeConstraint(exp_type, arg_expr.type3)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(sig_part)
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.FunctionCall):
|
if isinstance(inp, ourlang.FunctionCall):
|
||||||
@ -96,7 +96,7 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
# FIXME: Duplicate code with BinaryOp
|
# FIXME: Duplicate code with BinaryOp
|
||||||
|
|
||||||
type_var_map = {
|
type_var_map = {
|
||||||
x: type3types.PlaceholderForType([])
|
x: placeholders.PlaceholderForType([])
|
||||||
for x in inp.function.signature
|
for x in inp.function.signature
|
||||||
if isinstance(x, type3typeclasses.TypeVariable)
|
if isinstance(x, type3typeclasses.TypeVariable)
|
||||||
}
|
}
|
||||||
@ -117,12 +117,11 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
yield SameTypeConstraint(type_var_map[sig_part], arg_expr.type3)
|
yield SameTypeConstraint(type_var_map[sig_part], arg_expr.type3)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(sig_part, type3typeclasses.TypeReference):
|
if isinstance(sig_part, type3types.Type3):
|
||||||
# On key error: We probably have to a lot of work to do refactoring
|
yield SameTypeConstraint(sig_part, arg_expr.type3)
|
||||||
# the type lookups
|
|
||||||
exp_type = type3types.LOOKUP_TABLE[sig_part.name]
|
|
||||||
yield SameTypeConstraint(exp_type, arg_expr.type3)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(sig_part)
|
||||||
return
|
return
|
||||||
|
|
||||||
yield SameTypeConstraint(inp.function.returns_type3, inp.type3,
|
yield SameTypeConstraint(inp.function.returns_type3, inp.type3,
|
||||||
@ -159,8 +158,12 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.AccessStructMember):
|
if isinstance(inp, ourlang.AccessStructMember):
|
||||||
|
assert isinstance(inp.struct_type3, type3types.Type3) # When does this happen?
|
||||||
|
st_args = prelude.struct.did_construct(inp.struct_type3)
|
||||||
|
assert st_args is not None # When does this happen?
|
||||||
|
|
||||||
yield from expression(ctx, inp.varref)
|
yield from expression(ctx, inp.varref)
|
||||||
yield SameTypeConstraint(inp.struct_type3.members[inp.member], inp.type3,
|
yield SameTypeConstraint(st_args[inp.member], inp.type3,
|
||||||
comment=f'The type of a struct member reference is the same as the type of struct member {inp.struct_type3.name}.{inp.member}')
|
comment=f'The type of a struct member reference is the same as the type of struct member {inp.struct_type3.name}.{inp.member}')
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -185,7 +188,7 @@ def statement_return(ctx: Context, fun: ourlang.Function, inp: ourlang.Statement
|
|||||||
def statement_if(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementIf) -> ConstraintGenerator:
|
def statement_if(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementIf) -> ConstraintGenerator:
|
||||||
yield from expression(ctx, inp.test)
|
yield from expression(ctx, inp.test)
|
||||||
|
|
||||||
yield SameTypeConstraint(inp.test.type3, type3types.bool_,
|
yield SameTypeConstraint(inp.test.type3, prelude.bool_,
|
||||||
comment='Must pass a boolean expression to if')
|
comment='Must pass a boolean expression to if')
|
||||||
|
|
||||||
for stmt in inp.statements:
|
for stmt in inp.statements:
|
||||||
|
|||||||
@ -12,14 +12,11 @@ from .constraints import (
|
|||||||
SubstitutionMap,
|
SubstitutionMap,
|
||||||
)
|
)
|
||||||
from .constraintsgenerator import phasm_type3_generate_constraints
|
from .constraintsgenerator import phasm_type3_generate_constraints
|
||||||
from .types import (
|
from .placeholders import (
|
||||||
IntType3,
|
|
||||||
PlaceholderForType,
|
PlaceholderForType,
|
||||||
PrimitiveType3,
|
|
||||||
StructType3,
|
|
||||||
Type3,
|
|
||||||
Type3OrPlaceholder,
|
Type3OrPlaceholder,
|
||||||
)
|
)
|
||||||
|
from .types import Type3
|
||||||
|
|
||||||
MAX_RESTACK_COUNT = 100
|
MAX_RESTACK_COUNT = 100
|
||||||
|
|
||||||
@ -143,7 +140,7 @@ def print_constraint(placeholder_id_map: Dict[int, str], constraint: ConstraintB
|
|||||||
print('- ' + txt.format(**act_fmt))
|
print('- ' + txt.format(**act_fmt))
|
||||||
|
|
||||||
def get_printable_type_name(inp: Type3OrPlaceholder, placeholder_id_map: Dict[int, str]) -> str:
|
def get_printable_type_name(inp: Type3OrPlaceholder, placeholder_id_map: Dict[int, str]) -> str:
|
||||||
if isinstance(inp, (PrimitiveType3, StructType3, IntType3, )):
|
if isinstance(inp, Type3):
|
||||||
return inp.name
|
return inp.name
|
||||||
|
|
||||||
if isinstance(inp, PlaceholderForType):
|
if isinstance(inp, PlaceholderForType):
|
||||||
|
|||||||
67
phasm/type3/placeholders.py
Normal file
67
phasm/type3/placeholders.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
Contains the placeholder for types for use in Phasm.
|
||||||
|
|
||||||
|
These are temporary while the compiler is calculating all the types and validating them.
|
||||||
|
"""
|
||||||
|
from typing import Any, Iterable, List, Optional, Protocol, Union
|
||||||
|
|
||||||
|
from .types import Type3
|
||||||
|
|
||||||
|
TYPE3_ASSERTION_ERROR = 'You must call phasm_type3 after calling phasm_parse before you can call any other method'
|
||||||
|
|
||||||
|
class ExpressionProtocol(Protocol):
|
||||||
|
"""
|
||||||
|
A protocol for classes that should be updated on substitution
|
||||||
|
"""
|
||||||
|
|
||||||
|
type3: 'Type3OrPlaceholder'
|
||||||
|
"""
|
||||||
|
The type to update
|
||||||
|
"""
|
||||||
|
|
||||||
|
class PlaceholderForType:
|
||||||
|
"""
|
||||||
|
A placeholder type, for when we don't know the final type yet
|
||||||
|
"""
|
||||||
|
__slots__ = ('update_on_substitution', 'resolve_as', )
|
||||||
|
|
||||||
|
update_on_substitution: List[ExpressionProtocol]
|
||||||
|
resolve_as: Optional[Type3]
|
||||||
|
|
||||||
|
def __init__(self, update_on_substitution: Iterable[ExpressionProtocol]) -> None:
|
||||||
|
self.update_on_substitution = [*update_on_substitution]
|
||||||
|
self.resolve_as = None
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
uos = ', '.join(repr(x) for x in self.update_on_substitution)
|
||||||
|
|
||||||
|
return f'PlaceholderForType({id(self)}, [{uos}])'
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f'PhFT_{id(self)}'
|
||||||
|
|
||||||
|
def __format__(self, format_spec: str) -> str:
|
||||||
|
if format_spec != 's':
|
||||||
|
raise TypeError('unsupported format string passed to Type3.__format__')
|
||||||
|
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
if isinstance(other, Type3):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not isinstance(other, PlaceholderForType):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
return self is other
|
||||||
|
|
||||||
|
def __ne__(self, other: Any) -> bool:
|
||||||
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return 0 # Valid but performs badly
|
||||||
|
|
||||||
|
def __bool__(self) -> bool:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
Type3OrPlaceholder = Union[Type3, PlaceholderForType]
|
||||||
@ -1,5 +1,7 @@
|
|||||||
from typing import Any, Dict, Iterable, List, Mapping, Optional, Union
|
from typing import Any, Dict, Iterable, List, Mapping, Optional, Union
|
||||||
|
|
||||||
|
from .types import Type3, TypeConstructor, TypeConstructor_Struct
|
||||||
|
|
||||||
|
|
||||||
class TypeVariable:
|
class TypeVariable:
|
||||||
__slots__ = ('letter', )
|
__slots__ = ('letter', )
|
||||||
@ -48,15 +50,12 @@ class Type3ClassMethod:
|
|||||||
|
|
||||||
type3_class: 'Type3Class'
|
type3_class: 'Type3Class'
|
||||||
name: str
|
name: str
|
||||||
signature: List[Union[TypeReference, TypeVariable]]
|
signature: List[Union[Type3, TypeVariable]]
|
||||||
|
|
||||||
def __init__(self, type3_class: 'Type3Class', name: str, signature: str) -> None:
|
def __init__(self, type3_class: 'Type3Class', name: str, signature: Iterable[Union[Type3, TypeVariable]]) -> None:
|
||||||
self.type3_class = type3_class
|
self.type3_class = type3_class
|
||||||
self.name = name
|
self.name = name
|
||||||
self.signature = [
|
self.signature = list(signature)
|
||||||
TypeVariable(x) if len(x) == 1 else TypeReference(x)
|
|
||||||
for x in signature.split(' -> ')
|
|
||||||
]
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'Type3ClassMethod({repr(self.type3_class)}, {repr(self.name)}, {repr(self.signature)})'
|
return f'Type3ClassMethod({repr(self.type3_class)}, {repr(self.name)}, {repr(self.signature)})'
|
||||||
@ -73,13 +72,13 @@ class Type3Class:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
args: Iterable[str],
|
args: Iterable[TypeVariable],
|
||||||
methods: Mapping[str, str],
|
methods: Mapping[str, Iterable[Union[Type3, TypeVariable]]],
|
||||||
operators: Mapping[str, str],
|
operators: Mapping[str, Iterable[Union[Type3, TypeVariable]]],
|
||||||
inherited_classes: Optional[List['Type3Class']] = None,
|
inherited_classes: Optional[List['Type3Class']] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.args = [TypeVariable(x) for x in args]
|
self.args = list(args)
|
||||||
self.methods = {
|
self.methods = {
|
||||||
k: Type3ClassMethod(self, k, v)
|
k: Type3ClassMethod(self, k, v)
|
||||||
for k, v in methods.items()
|
for k, v in methods.items()
|
||||||
@ -93,66 +92,8 @@ class Type3Class:
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
InternalPassAsPointer = Type3Class('InternalPassAsPointer', ['a'], methods={}, operators={})
|
def instance_type_class(cls: Type3Class, typ: Type3 | TypeConstructor[Any] | TypeConstructor_Struct) -> None:
|
||||||
|
if isinstance(typ, Type3):
|
||||||
Eq = Type3Class('Eq', ['a'], methods={}, operators={
|
typ.classes.add(cls)
|
||||||
'==': 'a -> a -> bool',
|
else:
|
||||||
'!=': 'a -> a -> bool',
|
typ.type_classes.add(cls)
|
||||||
# FIXME: Do we want to expose 'eqz'? Or is that a compiler optimization?
|
|
||||||
})
|
|
||||||
|
|
||||||
Ord = Type3Class('Ord', ['a'], methods={
|
|
||||||
'min': 'a -> a -> a',
|
|
||||||
'max': 'a -> a -> a',
|
|
||||||
}, operators={
|
|
||||||
'<': 'a -> a -> bool',
|
|
||||||
'<=': 'a -> a -> bool',
|
|
||||||
'>': 'a -> a -> bool',
|
|
||||||
'>=': 'a -> a -> bool',
|
|
||||||
}, inherited_classes=[Eq])
|
|
||||||
|
|
||||||
Bits = Type3Class('Bits', ['a'], methods={
|
|
||||||
'shl': 'a -> u32 -> a', # Logical shift left
|
|
||||||
'shr': 'a -> u32 -> a', # Logical shift right
|
|
||||||
'rotl': 'a -> u32 -> a', # Rotate bits left
|
|
||||||
'rotr': 'a -> u32 -> a', # Rotate bits right
|
|
||||||
# FIXME: Do we want to expose clz, ctz, popcnt?
|
|
||||||
}, operators={
|
|
||||||
'&': 'a -> a -> a', # Bit-wise and
|
|
||||||
'|': 'a -> a -> a', # Bit-wise or
|
|
||||||
'^': 'a -> a -> a', # Bit-wise xor
|
|
||||||
})
|
|
||||||
|
|
||||||
NatNum = Type3Class('NatNum', ['a'], methods={}, operators={
|
|
||||||
'+': 'a -> a -> a',
|
|
||||||
'-': 'a -> a -> a',
|
|
||||||
'*': 'a -> a -> a',
|
|
||||||
'<<': 'a -> u32 -> a', # Arithmic shift left
|
|
||||||
'>>': 'a -> u32 -> a', # Arithmic shift right
|
|
||||||
})
|
|
||||||
|
|
||||||
IntNum = Type3Class('IntNum', ['a'], methods={
|
|
||||||
'abs': 'a -> a',
|
|
||||||
'neg': 'a -> a',
|
|
||||||
}, operators={}, inherited_classes=[NatNum])
|
|
||||||
|
|
||||||
Integral = Type3Class('Eq', ['a'], methods={
|
|
||||||
}, operators={
|
|
||||||
'//': 'a -> a -> a',
|
|
||||||
'%': 'a -> a -> a',
|
|
||||||
}, inherited_classes=[NatNum])
|
|
||||||
|
|
||||||
Fractional = Type3Class('Fractional', ['a'], methods={
|
|
||||||
'ceil': 'a -> a',
|
|
||||||
'floor': 'a -> a',
|
|
||||||
'trunc': 'a -> a',
|
|
||||||
'nearest': 'a -> a',
|
|
||||||
}, operators={
|
|
||||||
'/': 'a -> a -> a',
|
|
||||||
}, inherited_classes=[NatNum])
|
|
||||||
|
|
||||||
Floating = Type3Class('Floating', ['a'], methods={
|
|
||||||
'sqrt': 'a -> a',
|
|
||||||
}, operators={}, inherited_classes=[Fractional])
|
|
||||||
|
|
||||||
# FIXME: Do we want to expose copysign?
|
|
||||||
|
|||||||
@ -1,51 +1,29 @@
|
|||||||
"""
|
"""
|
||||||
Contains the final types for use in Phasm
|
Contains the final types for use in Phasm, as well as construtors.
|
||||||
|
|
||||||
These are actual, instantiated types; not the abstract types that the
|
|
||||||
constraint generator works with.
|
|
||||||
"""
|
"""
|
||||||
from typing import (
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
Dict,
|
|
||||||
Generic,
|
Generic,
|
||||||
Iterable,
|
Iterable,
|
||||||
List,
|
|
||||||
Optional,
|
|
||||||
Protocol,
|
|
||||||
Set,
|
Set,
|
||||||
Tuple,
|
Tuple,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Union,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from .typeclasses import (
|
if TYPE_CHECKING:
|
||||||
Bits,
|
from .typeclasses import Type3Class
|
||||||
Eq,
|
|
||||||
Floating,
|
|
||||||
Fractional,
|
|
||||||
Integral,
|
|
||||||
InternalPassAsPointer,
|
|
||||||
IntNum,
|
|
||||||
NatNum,
|
|
||||||
Ord,
|
|
||||||
Type3Class,
|
|
||||||
)
|
|
||||||
|
|
||||||
TYPE3_ASSERTION_ERROR = 'You must call phasm_type3 after calling phasm_parse before you can call any other method'
|
|
||||||
|
|
||||||
class ExpressionProtocol(Protocol):
|
class KindArgument:
|
||||||
"""
|
pass
|
||||||
A protocol for classes that should be updated on substitution
|
|
||||||
"""
|
|
||||||
|
|
||||||
type3: 'Type3OrPlaceholder'
|
class Type3(KindArgument):
|
||||||
"""
|
|
||||||
The type to update
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Type3:
|
|
||||||
"""
|
"""
|
||||||
Base class for the type3 types
|
Base class for the type3 types
|
||||||
|
|
||||||
|
(Having a separate name makes it easier to distinguish from
|
||||||
|
Python's Type)
|
||||||
"""
|
"""
|
||||||
__slots__ = ('name', 'classes', )
|
__slots__ = ('name', 'classes', )
|
||||||
|
|
||||||
@ -54,12 +32,12 @@ class Type3:
|
|||||||
The name of the string, as parsed and outputted by codestyle.
|
The name of the string, as parsed and outputted by codestyle.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
classes: Set[Type3Class]
|
classes: Set['Type3Class']
|
||||||
"""
|
"""
|
||||||
The type classes that this type implements
|
The type classes that this type implements
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str, classes: Iterable[Type3Class]) -> None:
|
def __init__(self, name: str, classes: Iterable['Type3Class']) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.classes = set(classes)
|
self.classes = set(classes)
|
||||||
|
|
||||||
@ -84,9 +62,6 @@ class Type3:
|
|||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
def __eq__(self, other: Any) -> bool:
|
def __eq__(self, other: Any) -> bool:
|
||||||
if isinstance(other, PlaceholderForType):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not isinstance(other, Type3):
|
if not isinstance(other, Type3):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@ -101,19 +76,15 @@ class Type3:
|
|||||||
def __bool__(self) -> bool:
|
def __bool__(self) -> bool:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class PrimitiveType3(Type3):
|
class IntType3(KindArgument):
|
||||||
"""
|
"""
|
||||||
Intermediate class to tell primitive types from others
|
Sometimes you can have an int on the type level, e.g. when using static arrays
|
||||||
"""
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
class IntType3(Type3):
|
|
||||||
"""
|
|
||||||
Sometimes you can have an int as type, e.g. when using static arrays
|
|
||||||
|
|
||||||
This is not the same as an int on the language level.
|
This is not the same as an int on the language level.
|
||||||
[1.0, 1.2] :: Float[2] :: * -> Int -> *
|
[1.0, 1.2] :: f32[2] :: * -> Int -> *
|
||||||
|
|
||||||
|
That is to say, you can create a static array of size two with each element
|
||||||
|
a f32 using f32[2].
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ('value', )
|
__slots__ = ('value', )
|
||||||
@ -121,15 +92,13 @@ class IntType3(Type3):
|
|||||||
value: int
|
value: int
|
||||||
|
|
||||||
def __init__(self, value: int) -> None:
|
def __init__(self, value: int) -> None:
|
||||||
super().__init__(str(value), [])
|
|
||||||
|
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __eq__(self, other: Any) -> bool:
|
def __eq__(self, other: Any) -> bool:
|
||||||
if isinstance(other, IntType3):
|
if isinstance(other, IntType3):
|
||||||
return self.value == other.value
|
return self.value == other.value
|
||||||
|
|
||||||
if isinstance(other, Type3):
|
if isinstance(other, KindArgument):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@ -137,53 +106,6 @@ class IntType3(Type3):
|
|||||||
def __hash__(self) -> int:
|
def __hash__(self) -> int:
|
||||||
return hash(self.value)
|
return hash(self.value)
|
||||||
|
|
||||||
class PlaceholderForType:
|
|
||||||
"""
|
|
||||||
A placeholder type, for when we don't know the final type yet
|
|
||||||
"""
|
|
||||||
__slots__ = ('update_on_substitution', 'resolve_as', )
|
|
||||||
|
|
||||||
update_on_substitution: List[ExpressionProtocol]
|
|
||||||
resolve_as: Optional[Type3]
|
|
||||||
|
|
||||||
def __init__(self, update_on_substitution: Iterable[ExpressionProtocol]) -> None:
|
|
||||||
self.update_on_substitution = [*update_on_substitution]
|
|
||||||
self.resolve_as = None
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
uos = ', '.join(repr(x) for x in self.update_on_substitution)
|
|
||||||
|
|
||||||
return f'PlaceholderForType({id(self)}, [{uos}])'
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return f'PhFT_{id(self)}'
|
|
||||||
|
|
||||||
def __format__(self, format_spec: str) -> str:
|
|
||||||
if format_spec != 's':
|
|
||||||
raise TypeError('unsupported format string passed to Type3.__format__')
|
|
||||||
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
def __eq__(self, other: Any) -> bool:
|
|
||||||
if isinstance(other, Type3):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not isinstance(other, PlaceholderForType):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
return self is other
|
|
||||||
|
|
||||||
def __ne__(self, other: Any) -> bool:
|
|
||||||
return not self.__eq__(other)
|
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
|
||||||
return 0 # Valid but performs badly
|
|
||||||
|
|
||||||
def __bool__(self) -> bool:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
Type3OrPlaceholder = Union[Type3, PlaceholderForType]
|
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
|
||||||
class TypeConstructor(Generic[T]):
|
class TypeConstructor(Generic[T]):
|
||||||
@ -197,28 +119,28 @@ class TypeConstructor(Generic[T]):
|
|||||||
The name of the type constructor
|
The name of the type constructor
|
||||||
"""
|
"""
|
||||||
|
|
||||||
classes: Set[Type3Class]
|
classes: Set['Type3Class']
|
||||||
"""
|
"""
|
||||||
The type classes that this constructor implements
|
The type classes that this constructor implements
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type_classes: Set[Type3Class]
|
type_classes: Set['Type3Class']
|
||||||
"""
|
"""
|
||||||
The type classes that the constructed types implement
|
The type classes that the constructed types implement
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_cache: dict[T, PrimitiveType3]
|
_cache: dict[T, Type3]
|
||||||
"""
|
"""
|
||||||
When constructing a type with the same arguments,
|
When constructing a type with the same arguments,
|
||||||
it should produce the exact same result.
|
it should produce the exact same result.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_reverse_cache: dict[PrimitiveType3, T]
|
_reverse_cache: dict[Type3, T]
|
||||||
"""
|
"""
|
||||||
Sometimes we need to know the key that created a type.
|
Sometimes we need to know the key that created a type.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str, classes: Iterable[Type3Class], type_classes: Iterable[Type3Class]) -> None:
|
def __init__(self, name: str, classes: Iterable['Type3Class'], type_classes: Iterable['Type3Class']) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.classes = set(classes)
|
self.classes = set(classes)
|
||||||
self.type_classes = set(type_classes)
|
self.type_classes = set(type_classes)
|
||||||
@ -227,186 +149,123 @@ class TypeConstructor(Generic[T]):
|
|||||||
self._reverse_cache = {}
|
self._reverse_cache = {}
|
||||||
|
|
||||||
def make_name(self, key: T) -> str:
|
def make_name(self, key: T) -> str:
|
||||||
|
"""
|
||||||
|
Renders the type's name based on the given arguments
|
||||||
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def did_construct(self, typ: PrimitiveType3) -> T | None:
|
def did_construct(self, typ: Type3) -> T | None:
|
||||||
|
"""
|
||||||
|
Was the given type constructed by this constructor?
|
||||||
|
|
||||||
|
If so, which arguments where used?
|
||||||
|
"""
|
||||||
return self._reverse_cache.get(typ)
|
return self._reverse_cache.get(typ)
|
||||||
|
|
||||||
def construct(self, key: T) -> PrimitiveType3:
|
def construct(self, key: T) -> Type3:
|
||||||
|
"""
|
||||||
|
Constructs the type by applying the given arguments to this
|
||||||
|
constructor.
|
||||||
|
"""
|
||||||
result = self._cache.get(key, None)
|
result = self._cache.get(key, None)
|
||||||
if result is None:
|
if result is None:
|
||||||
self._cache[key] = result = PrimitiveType3(self.make_name(key), self.type_classes)
|
self._cache[key] = result = Type3(self.make_name(key), self.type_classes)
|
||||||
self._reverse_cache[result] = key
|
self._reverse_cache[result] = key
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
class TypeConstructor_Type(TypeConstructor[PrimitiveType3]):
|
class TypeConstructor_Type(TypeConstructor[Type3]):
|
||||||
"""
|
"""
|
||||||
Base class type constructors of kind: * -> *
|
Base class type constructors of kind: * -> *
|
||||||
"""
|
"""
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
def __call__(self, arg: PrimitiveType3) -> PrimitiveType3:
|
def __call__(self, arg: Type3) -> Type3:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class TypeConstructor_TypeInt(TypeConstructor[Tuple[PrimitiveType3, IntType3]]):
|
class TypeConstructor_TypeInt(TypeConstructor[Tuple[Type3, IntType3]]):
|
||||||
"""
|
"""
|
||||||
Base class type constructors of kind: * -> Int -> *
|
Base class type constructors of kind: * -> Int -> *
|
||||||
|
|
||||||
|
Notably, static array.
|
||||||
"""
|
"""
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
def make_name(self, key: Tuple[PrimitiveType3, IntType3]) -> str:
|
def make_name(self, key: Tuple[Type3, IntType3]) -> str:
|
||||||
return f'{self.name} {key[0].name} {key[1].value}'
|
return f'{self.name} {key[0].name} {key[1].value}'
|
||||||
|
|
||||||
def __call__(self, arg0: PrimitiveType3, arg1: IntType3) -> PrimitiveType3:
|
def __call__(self, arg0: Type3, arg1: IntType3) -> Type3:
|
||||||
return self.construct((arg0, arg1))
|
return self.construct((arg0, arg1))
|
||||||
|
|
||||||
class TypeConstructor_TypeStar(TypeConstructor[Tuple[PrimitiveType3, ...]]):
|
class TypeConstructor_TypeStar(TypeConstructor[Tuple[Type3, ...]]):
|
||||||
"""
|
"""
|
||||||
Base class type constructors of variadic kind
|
Base class type constructors of variadic kind
|
||||||
|
|
||||||
|
Notably, tuple.
|
||||||
"""
|
"""
|
||||||
def __call__(self, *args: PrimitiveType3) -> PrimitiveType3:
|
def __call__(self, *args: Type3) -> Type3:
|
||||||
key: Tuple[PrimitiveType3, ...] = tuple(args)
|
key: Tuple[Type3, ...] = tuple(args)
|
||||||
return self.construct(key)
|
return self.construct(key)
|
||||||
|
|
||||||
class TypeConstructor_StaticArray(TypeConstructor_TypeInt):
|
class TypeConstructor_StaticArray(TypeConstructor_TypeInt):
|
||||||
def make_name(self, key: Tuple[PrimitiveType3, IntType3]) -> str:
|
def make_name(self, key: Tuple[Type3, IntType3]) -> str:
|
||||||
return f'{key[0].name}[{key[1].value}]'
|
return f'{key[0].name}[{key[1].value}]'
|
||||||
|
|
||||||
class TypeConstructor_Tuple(TypeConstructor_TypeStar):
|
class TypeConstructor_Tuple(TypeConstructor_TypeStar):
|
||||||
def make_name(self, key: Tuple[PrimitiveType3, ...]) -> str:
|
def make_name(self, key: Tuple[Type3, ...]) -> str:
|
||||||
return '(' + ', '.join(x.name for x in key) + ', )'
|
return '(' + ', '.join(x.name for x in key) + ', )'
|
||||||
|
|
||||||
class StructType3(PrimitiveType3):
|
class TypeConstructor_Struct:
|
||||||
"""
|
"""
|
||||||
A Type3 struct with named members
|
Base class for type construtors
|
||||||
"""
|
"""
|
||||||
__slots__ = ('name', 'members', )
|
__slots__ = ('name', 'classes', 'type_classes', '_cache', '_reverse_cache')
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
"""
|
"""
|
||||||
The structs fully qualified name
|
The name of the type constructor
|
||||||
"""
|
"""
|
||||||
|
|
||||||
members: Dict[str, Type3]
|
classes: Set['Type3Class']
|
||||||
"""
|
"""
|
||||||
The struct's field definitions
|
The type classes that this constructor implements
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str, members: Dict[str, Type3]) -> None:
|
type_classes: Set['Type3Class']
|
||||||
super().__init__(name, [])
|
"""
|
||||||
|
The type classes that the constructed types implement
|
||||||
|
"""
|
||||||
|
|
||||||
|
_cache: dict[str, Type3]
|
||||||
|
"""
|
||||||
|
When constructing a type with the same arguments,
|
||||||
|
it should produce the exact same result.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_reverse_cache: dict[Type3, dict[str, Type3]]
|
||||||
|
"""
|
||||||
|
After construction you may need to look up the arguments
|
||||||
|
used for making the type
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name: str, classes: Iterable['Type3Class'], type_classes: Iterable['Type3Class']) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.members = dict(members)
|
self.classes = set(classes)
|
||||||
|
self.type_classes = set(type_classes)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
self._cache = {}
|
||||||
return f'StructType3(repr({self.name}), repr({self.members}))'
|
self._reverse_cache = {}
|
||||||
|
|
||||||
none = PrimitiveType3('none', [])
|
def did_construct(self, typ: Type3) -> dict[str, Type3] | None:
|
||||||
"""
|
"""
|
||||||
The none type, for when functions simply don't return anything. e.g., IO().
|
Was the given type constructed by this constructor?
|
||||||
"""
|
|
||||||
|
|
||||||
bool_ = PrimitiveType3('bool', [])
|
If so, which arguments where used?
|
||||||
"""
|
"""
|
||||||
The bool type, either True or False
|
return self._reverse_cache.get(typ)
|
||||||
|
|
||||||
Suffixes with an underscores, as it's a Python builtin
|
def __call__(self, name: str, args: dict[str, Type3], classes: Set['Type3Class']) -> Type3:
|
||||||
"""
|
result = Type3(name, classes | self.type_classes)
|
||||||
|
self._reverse_cache[result] = args
|
||||||
|
|
||||||
u8 = PrimitiveType3('u8', [Bits, Eq, Ord])
|
return result
|
||||||
"""
|
|
||||||
The unsigned 8-bit integer type.
|
|
||||||
|
|
||||||
Operations on variables employ modular arithmetic, with modulus 2^8.
|
|
||||||
"""
|
|
||||||
|
|
||||||
u32 = PrimitiveType3('u32', [Bits, Eq, Integral, NatNum, Ord])
|
|
||||||
"""
|
|
||||||
The unsigned 32-bit integer type.
|
|
||||||
|
|
||||||
Operations on variables employ modular arithmetic, with modulus 2^32.
|
|
||||||
"""
|
|
||||||
|
|
||||||
u64 = PrimitiveType3('u64', [Bits, Eq, Integral, NatNum, Ord])
|
|
||||||
"""
|
|
||||||
The unsigned 64-bit integer type.
|
|
||||||
|
|
||||||
Operations on variables employ modular arithmetic, with modulus 2^64.
|
|
||||||
"""
|
|
||||||
|
|
||||||
i8 = PrimitiveType3('i8', [Eq, Ord])
|
|
||||||
"""
|
|
||||||
The signed 8-bit integer type.
|
|
||||||
|
|
||||||
Operations on variables employ modular arithmetic, with modulus 2^8, but
|
|
||||||
with the middel point being 0.
|
|
||||||
"""
|
|
||||||
|
|
||||||
i32 = PrimitiveType3('i32', [Eq, Integral, IntNum, NatNum, Ord])
|
|
||||||
"""
|
|
||||||
The unsigned 32-bit integer type.
|
|
||||||
|
|
||||||
Operations on variables employ modular arithmetic, with modulus 2^32, but
|
|
||||||
with the middel point being 0.
|
|
||||||
"""
|
|
||||||
|
|
||||||
i64 = PrimitiveType3('i64', [Eq, Integral, IntNum, NatNum, Ord])
|
|
||||||
"""
|
|
||||||
The unsigned 64-bit integer type.
|
|
||||||
|
|
||||||
Operations on variables employ modular arithmetic, with modulus 2^64, but
|
|
||||||
with the middel point being 0.
|
|
||||||
"""
|
|
||||||
|
|
||||||
f32 = PrimitiveType3('f32', [Eq, Floating, Fractional, IntNum, NatNum, Ord])
|
|
||||||
"""
|
|
||||||
A 32-bits IEEE 754 float, of 32 bits width.
|
|
||||||
"""
|
|
||||||
|
|
||||||
f64 = PrimitiveType3('f64', [Eq, Floating, Fractional, IntNum, NatNum, Ord])
|
|
||||||
"""
|
|
||||||
A 32-bits IEEE 754 float, of 64 bits width.
|
|
||||||
"""
|
|
||||||
|
|
||||||
bytes_ = PrimitiveType3('bytes', [])
|
|
||||||
"""
|
|
||||||
This is a runtime-determined length piece of memory that can be indexed at runtime.
|
|
||||||
"""
|
|
||||||
|
|
||||||
static_array = TypeConstructor_StaticArray('static_array', [], [
|
|
||||||
Eq,
|
|
||||||
InternalPassAsPointer,
|
|
||||||
])
|
|
||||||
"""
|
|
||||||
A type constructor.
|
|
||||||
|
|
||||||
Any static array is a fixed length piece of memory that can be indexed at runtime.
|
|
||||||
|
|
||||||
It should be applied with one argument. It has a runtime-dynamic length
|
|
||||||
of the same type repeated.
|
|
||||||
"""
|
|
||||||
|
|
||||||
tuple_ = TypeConstructor_Tuple('tuple', [], [
|
|
||||||
InternalPassAsPointer,
|
|
||||||
])
|
|
||||||
"""
|
|
||||||
This is a fixed length piece of memory.
|
|
||||||
|
|
||||||
It should be applied with zero or more arguments. It has a compile time
|
|
||||||
determined length, and each argument can be different.
|
|
||||||
"""
|
|
||||||
|
|
||||||
LOOKUP_TABLE: Dict[str, PrimitiveType3] = {
|
|
||||||
'none': none,
|
|
||||||
'bool': bool_,
|
|
||||||
'u8': u8,
|
|
||||||
'u32': u32,
|
|
||||||
'u64': u64,
|
|
||||||
'i8': i8,
|
|
||||||
'i32': i32,
|
|
||||||
'i64': i64,
|
|
||||||
'f32': f32,
|
|
||||||
'f64': f64,
|
|
||||||
'bytes': bytes_,
|
|
||||||
}
|
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import struct
|
|||||||
import sys
|
import sys
|
||||||
from typing import Any, Generator, Iterable, List, TextIO, Union
|
from typing import Any, Generator, Iterable, List, TextIO, Union
|
||||||
|
|
||||||
from phasm import compiler
|
from phasm import compiler, prelude
|
||||||
from phasm.codestyle import phasm_render
|
from phasm.codestyle import phasm_render
|
||||||
from phasm.runtime import calculate_alloc_size
|
from phasm.runtime import calculate_alloc_size
|
||||||
from phasm.type3 import typeclasses as type3classes
|
from phasm.type3 import placeholders as type3placeholders
|
||||||
from phasm.type3 import types as type3types
|
from phasm.type3 import types as type3types
|
||||||
|
|
||||||
from . import runners
|
from . import runners
|
||||||
@ -65,43 +65,44 @@ class Suite:
|
|||||||
runner.interpreter_dump_memory(sys.stderr)
|
runner.interpreter_dump_memory(sys.stderr)
|
||||||
|
|
||||||
for arg, arg_typ in zip(args, func_args):
|
for arg, arg_typ in zip(args, func_args):
|
||||||
assert not isinstance(arg_typ, type3types.PlaceholderForType), \
|
assert not isinstance(arg_typ, type3placeholders.PlaceholderForType), \
|
||||||
'Cannot call polymorphic function from outside'
|
'Cannot call polymorphic function from outside'
|
||||||
|
|
||||||
if arg_typ in (type3types.u8, type3types.u32, type3types.u64, ):
|
if arg_typ in (prelude.u8, prelude.u32, prelude.u64, ):
|
||||||
assert isinstance(arg, int)
|
assert isinstance(arg, int)
|
||||||
wasm_args.append(arg)
|
wasm_args.append(arg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if arg_typ in (type3types.i8, type3types.i32, type3types.i64, ):
|
if arg_typ in (prelude.i8, prelude.i32, prelude.i64, ):
|
||||||
assert isinstance(arg, int)
|
assert isinstance(arg, int)
|
||||||
wasm_args.append(arg)
|
wasm_args.append(arg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if arg_typ in (type3types.f32, type3types.f64, ):
|
if arg_typ in (prelude.f32, prelude.f64, ):
|
||||||
assert isinstance(arg, float)
|
assert isinstance(arg, float)
|
||||||
wasm_args.append(arg)
|
wasm_args.append(arg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if arg_typ is type3types.bytes_:
|
if arg_typ is prelude.bytes_:
|
||||||
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
||||||
wasm_args.append(adr)
|
wasm_args.append(adr)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert isinstance(arg_typ, type3types.PrimitiveType3)
|
assert isinstance(arg_typ, type3types.Type3)
|
||||||
sa_args = type3types.static_array.did_construct(arg_typ)
|
sa_args = prelude.static_array.did_construct(arg_typ)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
||||||
wasm_args.append(adr)
|
wasm_args.append(adr)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
tp_args = type3types.tuple_.did_construct(arg_typ)
|
tp_args = prelude.tuple_.did_construct(arg_typ)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
||||||
wasm_args.append(adr)
|
wasm_args.append(adr)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(arg_typ, type3types.StructType3):
|
st_args = prelude.struct.did_construct(arg_typ)
|
||||||
|
if st_args is not None:
|
||||||
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
||||||
wasm_args.append(adr)
|
wasm_args.append(adr)
|
||||||
continue
|
continue
|
||||||
@ -145,41 +146,39 @@ def _write_memory_stored_value(
|
|||||||
val_typ: type3types.Type3,
|
val_typ: type3types.Type3,
|
||||||
val: Any,
|
val: Any,
|
||||||
) -> int:
|
) -> int:
|
||||||
if val_typ is type3types.bytes_:
|
if val_typ is prelude.bytes_:
|
||||||
adr2 = _allocate_memory_stored_value(runner, val_typ, val)
|
adr2 = _allocate_memory_stored_value(runner, val_typ, val)
|
||||||
runner.interpreter_write_memory(adr, compiler.module_data_u32(adr2))
|
runner.interpreter_write_memory(adr, compiler.module_data_u32(adr2))
|
||||||
return 4
|
return 4
|
||||||
|
|
||||||
if isinstance(val_typ, type3types.StructType3):
|
st_args = prelude.struct.did_construct(val_typ)
|
||||||
|
if st_args is not None:
|
||||||
adr2 = _allocate_memory_stored_value(runner, val_typ, val)
|
adr2 = _allocate_memory_stored_value(runner, val_typ, val)
|
||||||
runner.interpreter_write_memory(adr, compiler.module_data_u32(adr2))
|
runner.interpreter_write_memory(adr, compiler.module_data_u32(adr2))
|
||||||
return 4
|
return 4
|
||||||
|
|
||||||
if isinstance(val_typ, type3types.PrimitiveType3):
|
sa_args = prelude.static_array.did_construct(val_typ)
|
||||||
sa_args = type3types.static_array.did_construct(val_typ)
|
if sa_args is not None:
|
||||||
if sa_args is not None:
|
adr2 = _allocate_memory_stored_value(runner, val_typ, val)
|
||||||
adr2 = _allocate_memory_stored_value(runner, val_typ, val)
|
runner.interpreter_write_memory(adr, compiler.module_data_u32(adr2))
|
||||||
runner.interpreter_write_memory(adr, compiler.module_data_u32(adr2))
|
return 4
|
||||||
return 4
|
|
||||||
|
|
||||||
tp_args = type3types.tuple_.did_construct(val_typ)
|
tp_args = prelude.tuple_.did_construct(val_typ)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
adr2 = _allocate_memory_stored_value(runner, val_typ, val)
|
adr2 = _allocate_memory_stored_value(runner, val_typ, val)
|
||||||
runner.interpreter_write_memory(adr, compiler.module_data_u32(adr2))
|
runner.interpreter_write_memory(adr, compiler.module_data_u32(adr2))
|
||||||
return 4
|
return 4
|
||||||
|
|
||||||
to_write = WRITE_LOOKUP_MAP[val_typ.name](val)
|
to_write = WRITE_LOOKUP_MAP[val_typ.name](val)
|
||||||
runner.interpreter_write_memory(adr, to_write)
|
runner.interpreter_write_memory(adr, to_write)
|
||||||
return len(to_write)
|
return len(to_write)
|
||||||
|
|
||||||
raise NotImplementedError(val_typ, val)
|
|
||||||
|
|
||||||
def _allocate_memory_stored_value(
|
def _allocate_memory_stored_value(
|
||||||
runner: runners.RunnerBase,
|
runner: runners.RunnerBase,
|
||||||
val_typ: type3types.Type3,
|
val_typ: type3types.Type3,
|
||||||
val: Any
|
val: Any
|
||||||
) -> int:
|
) -> int:
|
||||||
if val_typ is type3types.bytes_:
|
if val_typ is prelude.bytes_:
|
||||||
assert isinstance(val, bytes)
|
assert isinstance(val, bytes)
|
||||||
|
|
||||||
adr = runner.call('stdlib.types.__alloc_bytes__', len(val))
|
adr = runner.call('stdlib.types.__alloc_bytes__', len(val))
|
||||||
@ -189,8 +188,7 @@ def _allocate_memory_stored_value(
|
|||||||
runner.interpreter_write_memory(adr + 4, val)
|
runner.interpreter_write_memory(adr + 4, val)
|
||||||
return adr
|
return adr
|
||||||
|
|
||||||
assert isinstance(val_typ, type3types.PrimitiveType3)
|
sa_args = prelude.static_array.did_construct(val_typ)
|
||||||
sa_args = type3types.static_array.did_construct(val_typ)
|
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
assert isinstance(val, tuple)
|
assert isinstance(val, tuple)
|
||||||
|
|
||||||
@ -211,7 +209,7 @@ def _allocate_memory_stored_value(
|
|||||||
|
|
||||||
val_el_typ: type3types.Type3
|
val_el_typ: type3types.Type3
|
||||||
|
|
||||||
tp_args = type3types.tuple_.did_construct(val_typ)
|
tp_args = prelude.tuple_.did_construct(val_typ)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
assert isinstance(val, tuple)
|
assert isinstance(val, tuple)
|
||||||
|
|
||||||
@ -224,12 +222,13 @@ def _allocate_memory_stored_value(
|
|||||||
|
|
||||||
offset = adr
|
offset = adr
|
||||||
for val_el_val, val_el_typ in zip(val, tp_args):
|
for val_el_val, val_el_typ in zip(val, tp_args):
|
||||||
assert not isinstance(val_el_typ, type3types.PlaceholderForType)
|
assert not isinstance(val_el_typ, type3placeholders.PlaceholderForType)
|
||||||
|
|
||||||
offset += _write_memory_stored_value(runner, offset, val_el_typ, val_el_val)
|
offset += _write_memory_stored_value(runner, offset, val_el_typ, val_el_val)
|
||||||
return adr
|
return adr
|
||||||
|
|
||||||
if isinstance(val_typ, type3types.StructType3):
|
st_args = prelude.struct.did_construct(val_typ)
|
||||||
|
if st_args is not None:
|
||||||
assert isinstance(val, dict)
|
assert isinstance(val, dict)
|
||||||
|
|
||||||
alloc_size = calculate_alloc_size(val_typ)
|
alloc_size = calculate_alloc_size(val_typ)
|
||||||
@ -237,11 +236,11 @@ def _allocate_memory_stored_value(
|
|||||||
assert isinstance(adr, int)
|
assert isinstance(adr, int)
|
||||||
sys.stderr.write(f'Allocation 0x{adr:08x} {repr(val)}\n')
|
sys.stderr.write(f'Allocation 0x{adr:08x} {repr(val)}\n')
|
||||||
|
|
||||||
assert list(val.keys()) == list(val_typ.members.keys())
|
assert list(val.keys()) == list(st_args)
|
||||||
|
|
||||||
offset = adr
|
offset = adr
|
||||||
for val_el_name, val_el_typ in val_typ.members.items():
|
for val_el_name, val_el_typ in st_args.items():
|
||||||
assert not isinstance(val_el_typ, type3types.PlaceholderForType)
|
assert not isinstance(val_el_typ, type3placeholders.PlaceholderForType)
|
||||||
|
|
||||||
val_el_val = val[val_el_name]
|
val_el_val = val[val_el_name]
|
||||||
offset += _write_memory_stored_value(runner, offset, val_el_typ, val_el_val)
|
offset += _write_memory_stored_value(runner, offset, val_el_typ, val_el_val)
|
||||||
@ -256,18 +255,18 @@ def _load_memory_stored_returned_value(
|
|||||||
) -> Any:
|
) -> Any:
|
||||||
ret_type3 = runner.phasm_ast.functions[func_name].returns_type3
|
ret_type3 = runner.phasm_ast.functions[func_name].returns_type3
|
||||||
|
|
||||||
if ret_type3 is type3types.none:
|
if ret_type3 is prelude.none:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if ret_type3 is type3types.bool_:
|
if ret_type3 is prelude.bool_:
|
||||||
assert isinstance(wasm_value, int), wasm_value
|
assert isinstance(wasm_value, int), wasm_value
|
||||||
return 0 != wasm_value
|
return 0 != wasm_value
|
||||||
|
|
||||||
if ret_type3 in (type3types.i8, type3types.i32, type3types.i64):
|
if ret_type3 in (prelude.i8, prelude.i32, prelude.i64):
|
||||||
assert isinstance(wasm_value, int), wasm_value
|
assert isinstance(wasm_value, int), wasm_value
|
||||||
return wasm_value
|
return wasm_value
|
||||||
|
|
||||||
if ret_type3 in (type3types.u8, type3types.u32, type3types.u64):
|
if ret_type3 in (prelude.u8, prelude.u32, prelude.u64):
|
||||||
assert isinstance(wasm_value, int), wasm_value
|
assert isinstance(wasm_value, int), wasm_value
|
||||||
|
|
||||||
if wasm_value < 0:
|
if wasm_value < 0:
|
||||||
@ -284,98 +283,100 @@ def _load_memory_stored_returned_value(
|
|||||||
|
|
||||||
return wasm_value
|
return wasm_value
|
||||||
|
|
||||||
if ret_type3 in (type3types.f32, type3types.f64, ):
|
if ret_type3 in (prelude.f32, prelude.f64, ):
|
||||||
assert isinstance(wasm_value, float), wasm_value
|
assert isinstance(wasm_value, float), wasm_value
|
||||||
return wasm_value
|
return wasm_value
|
||||||
|
|
||||||
if ret_type3 is type3types.bytes_:
|
if ret_type3 is prelude.bytes_:
|
||||||
assert isinstance(wasm_value, int), wasm_value
|
assert isinstance(wasm_value, int), wasm_value
|
||||||
|
|
||||||
return _load_bytes_from_address(runner, ret_type3, wasm_value)
|
return _load_bytes_from_address(runner, ret_type3, wasm_value)
|
||||||
|
|
||||||
assert isinstance(ret_type3, type3types.PrimitiveType3) # Type hint
|
assert isinstance(ret_type3, type3types.Type3) # Type hint
|
||||||
|
|
||||||
sa_args = type3types.static_array.did_construct(ret_type3)
|
sa_args = prelude.static_array.did_construct(ret_type3)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
assert isinstance(wasm_value, int), wasm_value
|
assert isinstance(wasm_value, int), wasm_value
|
||||||
|
|
||||||
return _load_static_array_from_address(runner, sa_args[0], sa_args[1], wasm_value)
|
return _load_static_array_from_address(runner, sa_args[0], sa_args[1], wasm_value)
|
||||||
|
|
||||||
tp_args = type3types.tuple_.did_construct(ret_type3)
|
tp_args = prelude.tuple_.did_construct(ret_type3)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
assert isinstance(wasm_value, int), wasm_value
|
assert isinstance(wasm_value, int), wasm_value
|
||||||
|
|
||||||
return _load_tuple_from_address(runner, tp_args, wasm_value)
|
return _load_tuple_from_address(runner, tp_args, wasm_value)
|
||||||
|
|
||||||
if isinstance(ret_type3, type3types.StructType3):
|
st_args = prelude.struct.did_construct(ret_type3)
|
||||||
return _load_struct_from_address(runner, ret_type3, wasm_value)
|
if st_args is not None:
|
||||||
|
return _load_struct_from_address(runner, st_args, wasm_value)
|
||||||
|
|
||||||
raise NotImplementedError(ret_type3, wasm_value)
|
raise NotImplementedError(ret_type3, wasm_value)
|
||||||
|
|
||||||
def _unpack(runner: runners.RunnerBase, typ: type3types.Type3, inp: bytes) -> Any:
|
def _unpack(runner: runners.RunnerBase, typ: type3types.Type3, inp: bytes) -> Any:
|
||||||
if typ is type3types.u8:
|
if typ is prelude.u8:
|
||||||
# See compiler.py, LOAD_STORE_TYPE_MAP and module_data_u8
|
# See compiler.py, LOAD_STORE_TYPE_MAP and module_data_u8
|
||||||
assert len(inp) == 4
|
assert len(inp) == 4
|
||||||
return struct.unpack('<I', inp)[0]
|
return struct.unpack('<I', inp)[0]
|
||||||
|
|
||||||
if typ is type3types.u32:
|
if typ is prelude.u32:
|
||||||
assert len(inp) == 4
|
assert len(inp) == 4
|
||||||
return struct.unpack('<I', inp)[0]
|
return struct.unpack('<I', inp)[0]
|
||||||
|
|
||||||
if typ is type3types.u64:
|
if typ is prelude.u64:
|
||||||
assert len(inp) == 8
|
assert len(inp) == 8
|
||||||
return struct.unpack('<Q', inp)[0]
|
return struct.unpack('<Q', inp)[0]
|
||||||
|
|
||||||
if typ is type3types.i8:
|
if typ is prelude.i8:
|
||||||
# See compiler.py, LOAD_STORE_TYPE_MAP and module_data_i8
|
# See compiler.py, LOAD_STORE_TYPE_MAP and module_data_i8
|
||||||
assert len(inp) == 4
|
assert len(inp) == 4
|
||||||
return struct.unpack('<i', inp)[0]
|
return struct.unpack('<i', inp)[0]
|
||||||
|
|
||||||
if typ is type3types.i32:
|
if typ is prelude.i32:
|
||||||
assert len(inp) == 4
|
assert len(inp) == 4
|
||||||
return struct.unpack('<i', inp)[0]
|
return struct.unpack('<i', inp)[0]
|
||||||
|
|
||||||
if typ is type3types.i64:
|
if typ is prelude.i64:
|
||||||
assert len(inp) == 8
|
assert len(inp) == 8
|
||||||
return struct.unpack('<q', inp)[0]
|
return struct.unpack('<q', inp)[0]
|
||||||
|
|
||||||
if typ is type3types.f32:
|
if typ is prelude.f32:
|
||||||
assert len(inp) == 4
|
assert len(inp) == 4
|
||||||
return struct.unpack('<f', inp)[0]
|
return struct.unpack('<f', inp)[0]
|
||||||
|
|
||||||
if typ is type3types.f64:
|
if typ is prelude.f64:
|
||||||
assert len(inp) == 8
|
assert len(inp) == 8
|
||||||
return struct.unpack('<d', inp)[0]
|
return struct.unpack('<d', inp)[0]
|
||||||
|
|
||||||
if typ is type3types.bytes_:
|
if typ is prelude.bytes_:
|
||||||
# Note: For bytes, inp should contain a 4 byte pointer
|
# Note: For bytes, inp should contain a 4 byte pointer
|
||||||
assert len(inp) == 4
|
assert len(inp) == 4
|
||||||
adr = struct.unpack('<I', inp)[0]
|
adr = struct.unpack('<I', inp)[0]
|
||||||
|
|
||||||
return _load_bytes_from_address(runner, typ, adr)
|
return _load_bytes_from_address(runner, typ, adr)
|
||||||
|
|
||||||
if type3classes.InternalPassAsPointer in typ.classes:
|
if prelude.InternalPassAsPointer in typ.classes:
|
||||||
# Note: For applied types, inp should contain a 4 byte pointer
|
# Note: For applied types, inp should contain a 4 byte pointer
|
||||||
assert len(inp) == 4
|
assert len(inp) == 4
|
||||||
adr = struct.unpack('<I', inp)[0]
|
adr = struct.unpack('<I', inp)[0]
|
||||||
|
|
||||||
assert isinstance(typ, type3types.PrimitiveType3)
|
assert isinstance(typ, type3types.Type3)
|
||||||
|
|
||||||
sa_args = type3types.static_array.did_construct(typ)
|
sa_args = prelude.static_array.did_construct(typ)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
return _load_static_array_from_address(runner, sa_type, sa_len, adr)
|
return _load_static_array_from_address(runner, sa_type, sa_len, adr)
|
||||||
|
|
||||||
tp_args = type3types.tuple_.did_construct(typ)
|
tp_args = prelude.tuple_.did_construct(typ)
|
||||||
if tp_args is not None:
|
if tp_args is not None:
|
||||||
return _load_tuple_from_address(runner, tp_args, adr)
|
return _load_tuple_from_address(runner, tp_args, adr)
|
||||||
|
|
||||||
if isinstance(typ, type3types.StructType3):
|
st_args = prelude.struct.did_construct(typ)
|
||||||
# Note: For structs, inp should contain a 4 byte pointer
|
if st_args is not None:
|
||||||
assert len(inp) == 4
|
# Note: For structs, inp should contain a 4 byte pointer
|
||||||
adr = struct.unpack('<I', inp)[0]
|
assert len(inp) == 4
|
||||||
|
adr = struct.unpack('<I', inp)[0]
|
||||||
|
|
||||||
return _load_struct_from_address(runner, typ, adr)
|
return _load_struct_from_address(runner, st_args, adr)
|
||||||
|
|
||||||
raise NotImplementedError(typ, inp)
|
raise NotImplementedError(typ, inp)
|
||||||
|
|
||||||
@ -393,10 +394,10 @@ def _split_read_bytes(all_bytes: bytes, split_sizes: Iterable[int]) -> Generator
|
|||||||
yield all_bytes[offset:offset + size]
|
yield all_bytes[offset:offset + size]
|
||||||
offset += size
|
offset += size
|
||||||
|
|
||||||
def _load_static_array_from_address(runner: runners.RunnerBase, sub_typ: type3types.PrimitiveType3, len_typ: type3types.IntType3, adr: int) -> Any:
|
def _load_static_array_from_address(runner: runners.RunnerBase, sub_typ: type3types.Type3, len_typ: type3types.IntType3, adr: int) -> Any:
|
||||||
sys.stderr.write(f'Reading 0x{adr:08x} {sub_typ:s} {len_typ:s}\n')
|
sys.stderr.write(f'Reading 0x{adr:08x} {sub_typ:s} {len_typ:s}\n')
|
||||||
|
|
||||||
assert not isinstance(sub_typ, type3types.PlaceholderForType)
|
assert not isinstance(sub_typ, type3placeholders.PlaceholderForType)
|
||||||
assert isinstance(len_typ, type3types.IntType3)
|
assert isinstance(len_typ, type3types.IntType3)
|
||||||
|
|
||||||
sa_len = len_typ.value
|
sa_len = len_typ.value
|
||||||
@ -411,7 +412,7 @@ def _load_static_array_from_address(runner: runners.RunnerBase, sub_typ: type3ty
|
|||||||
for arg_bytes in _split_read_bytes(read_bytes, arg_sizes)
|
for arg_bytes in _split_read_bytes(read_bytes, arg_sizes)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _load_tuple_from_address(runner: runners.RunnerBase, typ_args: tuple[type3types.PrimitiveType3, ...], adr: int) -> Any:
|
def _load_tuple_from_address(runner: runners.RunnerBase, typ_args: tuple[type3types.Type3, ...], adr: int) -> Any:
|
||||||
sys.stderr.write(f'Reading 0x{adr:08x} tuple {len(typ_args)}\n')
|
sys.stderr.write(f'Reading 0x{adr:08x} tuple {len(typ_args)}\n')
|
||||||
|
|
||||||
arg_sizes = [
|
arg_sizes = [
|
||||||
@ -426,19 +427,13 @@ def _load_tuple_from_address(runner: runners.RunnerBase, typ_args: tuple[type3ty
|
|||||||
for arg_typ, arg_bytes in zip(typ_args, _split_read_bytes(read_bytes, arg_sizes))
|
for arg_typ, arg_bytes in zip(typ_args, _split_read_bytes(read_bytes, arg_sizes))
|
||||||
)
|
)
|
||||||
|
|
||||||
def _load_struct_from_address(runner: runners.RunnerBase, typ: type3types.Type3, adr: int) -> Any:
|
def _load_struct_from_address(runner: runners.RunnerBase, st_args: dict[str, type3types.Type3], adr: int) -> Any:
|
||||||
sys.stderr.write(f'Reading 0x{adr:08x} {typ:s}\n')
|
sys.stderr.write(f'Reading 0x{adr:08x} struct {list(st_args)}\n')
|
||||||
|
|
||||||
assert isinstance(typ, type3types.StructType3)
|
name_list = list(st_args)
|
||||||
|
|
||||||
name_list = list(typ.members)
|
typ_list = list(st_args.values())
|
||||||
|
assert len(typ_list) == len(st_args)
|
||||||
typ_list = [
|
|
||||||
x
|
|
||||||
for x in typ.members.values()
|
|
||||||
if not isinstance(x, type3types.PlaceholderForType)
|
|
||||||
]
|
|
||||||
assert len(typ_list) == len(typ.members)
|
|
||||||
|
|
||||||
arg_sizes = [
|
arg_sizes = [
|
||||||
calculate_alloc_size(x, is_member=True)
|
calculate_alloc_size(x, is_member=True)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user