Skip to content

Commit

Permalink
Merge pull request #16 from chibash/transpiler
Browse files Browse the repository at this point in the history
supports undefined type and undefined values
  • Loading branch information
maejima-fumika authored Oct 12, 2024
2 parents 8dd0a33 + 849b2b2 commit 3336a79
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 13 deletions.
2 changes: 1 addition & 1 deletion microcontroller/core/include/c-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ inline value_t ptr_to_value(pointer_t v) { return (value_t)(((uintptr_t)v & 0xff
inline bool is_ptr_value(value_t v) { return (v & 3) == 3; }

#define VALUE_NULL 3 // null pointer: 0000 ... 0011
#define VALUE_UNDEF 0
#define VALUE_UNDEF 3 // equivalent to VALUE_NULL
#define VALUE_ZERO 0 // integer 0
#define VALUE_FZERO 1 // float 0.0
#define VALUE_FALSE 0 // 0000 ... 0000 (integer 0)
Expand Down
4 changes: 3 additions & 1 deletion server/src/transpiler/code-generator/c-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ export function typeConversion(from: StaticType | undefined, to: StaticType | un
else
break
case BooleanT:
if (from === Integer || from === Float)
if (from === Integer)
return '('
else if (from === Float)
return '(int32_t)('
else if (from === Any)
return 'safe_value_to_bool('
else
Expand Down
5 changes: 5 additions & 0 deletions server/src/transpiler/code-generator/code-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ export class CodeGenerator extends visitor.NodeVisitor<VariableEnv> {
}

identifier(node: AST.Identifier, env: VariableEnv): void {
if (node.name === 'undefined') {
this.result.write('VALUE_UNDEF')
return
}

const info = env.table.lookup(node.name)
if (info !== undefined) {
if (info.isFunction) {
Expand Down
5 changes: 5 additions & 0 deletions server/src/transpiler/type-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ export default class TypeChecker<Info extends NameInfo> extends visitor.NodeVisi
}

identifier(node: AST.Identifier, names: NameTable<Info>): void {
if (node.name === 'undefined') {
this.result = Null
return
}

const nameInfo = names.lookup(node.name)
if (nameInfo !== undefined) {
const info = nameInfo as NameInfo
Expand Down
4 changes: 3 additions & 1 deletion server/src/transpiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ export class ArrayType extends ObjectType {
export function typeToString(type: StaticType): string {
if (type instanceof CompositeType)
return type.sourceName()
else if (type === Null)
return 'undefined'
else
return type
}
Expand Down Expand Up @@ -161,7 +163,7 @@ export function isSubtype(subtype: StaticType, type: StaticType): boolean {
|| subtype === StringT && type === objectType)
return true
else if (type === BooleanT)
return subtype !== Void && subtype !== Any
return subtype === BooleanT
else if (subtype instanceof CompositeType)
return subtype.isSubtypeOf(type)
else
Expand Down
40 changes: 32 additions & 8 deletions server/tests/transpiler/code-generator/code-generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ test('boolean conditions', () => {
let c: any = 3
while (c)
if (c-- < 0)
b = null
b = true
else if (c < -10) {
let str: any = null
let k = str + 1
Expand Down Expand Up @@ -70,10 +70,33 @@ test('boolean conditions', () => {
expect(compileAndRun(src)).toEqual('')
})

test('wrong assignment to boolean', () => {
const src = `
let b = true
b = null
`

expect(() => { compileAndRun(src) }).toThrow(/assignable to type 'boolean'/)

const src2 = `
let b = true
b = 3
`

expect(() => { compileAndRun(src2) }).toThrow(/assignable to type 'boolean'/)

const src3 = `
let b = true
b = 'foo'
`

expect(() => { compileAndRun(src2) }).toThrow(/assignable to type 'boolean'/)
})

test('literals', () => {
const src = `
function foo(n: integer) {
const empty = null
const empty = null // or undefined
const i = n
const f = 7.4
const b1 = true
Expand All @@ -89,12 +112,12 @@ test('literals', () => {
}
foo(33)
`
expect(compileAndRun(src)).toBe('null\n33\n7.400000\n1\n0\ntest\n')
expect(compileAndRun(src)).toBe('undefined\n33\n7.400000\n1\n0\ntest\n')
})

test('undefined', () => {
const src = 'const k = undefined'
expect(() => { compileAndRun(src) }).toThrow(/unknown name: undefined/)
compileAndRun(src)
})

test('control structuers', () => {
Expand Down Expand Up @@ -658,9 +681,10 @@ test('typeof operator', () => {
print(typeof('foo'))
print(typeof([1, 2, 3]))
print(typeof(null))
print(typeof(undefined))
print(typeof(foo))
`
expect(compileAndRun(src)).toBe('integer\ninteger\nstring\ninteger[]\nnull\n(any) => any\n')
expect(compileAndRun(src)).toBe('integer\ninteger\nstring\ninteger[]\nundefined\nundefined\n(any) => any\n')
})

test('++/-- operator', () => {
Expand Down Expand Up @@ -828,7 +852,7 @@ test('any to null', () => {
print(foo(null))
`

expect(compileAndRun(src)).toBe('null\n')
expect(compileAndRun(src)).toBe('undefined\n')
})

test('null to any or string', () => {
Expand All @@ -847,7 +871,7 @@ test('null to any or string', () => {
}
`

expect(compileAndRun(src)).toBe('null\n')
expect(compileAndRun(src)).toBe('undefined\n')
expect(() => compileAndRun(src2)).toThrow(/not assignable.*line 3/)
})

Expand Down Expand Up @@ -954,7 +978,7 @@ test('function call', () => {
print(baz(null, [1, 2], 11, 'baz2'))
`

expect(compileAndRun(src)).toBe([7, 3, '7.400000', 'null', 1, 'baz2', 11].join('\n') + '\n')
expect(compileAndRun(src)).toBe([7, 3, '7.400000', 'undefined', 1, 'baz2', 11].join('\n') + '\n')
})

test('array access', () => {
Expand Down
4 changes: 2 additions & 2 deletions server/tests/transpiler/code-generator/test-code-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ static void fbody_print(value_t self, value_t m) {
printf("%d\\n", value_to_int(m));
else if (is_float_value(m))
printf("%f\\n", value_to_float(m));
else if (m == VALUE_NULL)
puts("null");
else if (m == VALUE_NULL || m == VALUE_UNDEF)
puts("undefined");
else if (gc_is_string_literal(m))
puts(gc_string_literal_cstr(m));
else
Expand Down

0 comments on commit 3336a79

Please sign in to comment.