Skip to content

Commit

Permalink
Merge pull request #17 from chibash/transpiler
Browse files Browse the repository at this point in the history
supports % and %= for any-type operands
  • Loading branch information
maejima-fumika authored Oct 13, 2024
2 parents 3336a79 + 7894967 commit 5777704
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 5 deletions.
2 changes: 2 additions & 0 deletions microcontroller/core/include/c-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ extern value_t CR_SECTION any_add(value_t a, value_t b);
extern value_t CR_SECTION any_subtract(value_t a, value_t b);
extern value_t CR_SECTION any_multiply(value_t a, value_t b);
extern value_t CR_SECTION any_divide(value_t a, value_t b);
extern value_t CR_SECTION any_modulo(value_t a, value_t b);

extern bool CR_SECTION any_less(value_t a, value_t b);
extern bool CR_SECTION any_less_eq(value_t a, value_t b);
Expand All @@ -141,6 +142,7 @@ extern value_t CR_SECTION any_add_assign(value_t* a, value_t b);
extern value_t CR_SECTION any_subtract_assign(value_t* a, value_t b);
extern value_t CR_SECTION any_multiply_assign(value_t* a, value_t b);
extern value_t CR_SECTION any_divide_assign(value_t* a, value_t b);
extern value_t CR_SECTION any_modulo_assign(value_t* a, value_t b);

extern value_t CR_SECTION any_increment(value_t* expr);
extern value_t CR_SECTION any_decrement(value_t* expr);
Expand Down
16 changes: 16 additions & 0 deletions microcontroller/core/src/c-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,14 @@ ANY_OP_FUNC(subtract,-)
ANY_OP_FUNC(multiply,*)
ANY_OP_FUNC(divide,/)

value_t any_modulo(value_t a, value_t b) {
if (is_int_value(a))
if (is_int_value(b))
return int_to_value(value_to_int(a) % value_to_int(b));

return runtime_type_error("bad operand for %%");
}

#define ANY_CMP_FUNC(name, op) \
bool any_##name(value_t a, value_t b) {\
if (is_int_value(a)) {\
Expand Down Expand Up @@ -323,6 +331,14 @@ ANY_ASSIGN_OP_FUNC(subtract,-)
ANY_ASSIGN_OP_FUNC(multiply,*)
ANY_ASSIGN_OP_FUNC(divide,/)

value_t any_modulo_assign(value_t* a, value_t b) {
if (is_int_value(*a))
if (is_int_value(b))
return *a = int_to_value(value_to_int(*a) % value_to_int(b));

return runtime_type_error("bad operand for %%=");
}

#define ANY_UPDATE(name, op, code) \
value_t any_##name(value_t* expr) {\
value_t v;\
Expand Down
4 changes: 4 additions & 0 deletions server/src/transpiler/code-generator/c-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ export function arithmeticOpForAny(op: string) {
return 'any_multiply'
case '/':
return 'any_divide'
case '%':
return 'any_modulo'
case '+=':
return 'any_add_assign'
case '-=':
Expand All @@ -211,6 +213,8 @@ export function arithmeticOpForAny(op: string) {
return 'any_multiply_assign'
case '/=':
return 'any_divide_assign'
case '%=':
return 'any_modulo_assign'
case 'i': // ++v
return 'any_increment'
case 'p': // v++
Expand Down
6 changes: 3 additions & 3 deletions server/src/transpiler/code-generator/code-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -862,9 +862,9 @@ export class CodeGenerator extends visitor.NodeVisitor<VariableEnv> {
if (op === '==' || op === '!=' || op === '===' || op === '!==')
this.equalityExpression(op, left, right, env)
else if (op === '<' || op === '<=' || op === '>' || op === '>='
|| op === '+' || op === '-' || op === '*' || op === '/')
|| op === '+' || op === '-' || op === '*' || op === '/' || op === '%')
this.basicBinaryExpression(op, left, right, env)
else if (op === '|' || op === '^' || op === '&' || op === '%' || op === '<<' || op === '>>') {
else if (op === '|' || op === '^' || op === '&' || op === '<<' || op === '>>') {
// both left and right are integer or float.
this.numericBinaryExprssion(op, left, right, env)
}
Expand Down Expand Up @@ -903,7 +903,7 @@ export class CodeGenerator extends visitor.NodeVisitor<VariableEnv> {
this.numericBinaryExprssion(op2, left, right, env)
}

// +, -, *, /, <, <=, ... for integer, float, or any-type values
// +, -, *, /, %, <, <=, ... for integer, float, or any-type values
private basicBinaryExpression(op: string, left: AST.Node, right: AST.Node, env: VariableEnv): void {
const left_type = this.needsCoercion(left)
const right_type = this.needsCoercion(right)
Expand Down
23 changes: 21 additions & 2 deletions server/src/transpiler/type-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,18 @@ export default class TypeChecker<Info extends NameInfo> extends visitor.NodeVisi
else
this.result = Integer
}
else if (op === '|' || op === '^' || op === '&' || op === '%' || op === '<<' || op === '>>' || op === '>>>') {
else if (op === '%') {
this.assert((left_type === Integer || left_type === Any) && (right_type === Integer || right_type === Any),
'invalid operands to %. They must be integer or any', node)
if (left_type === Any || right_type === Any) {
this.addCoercion(node.left, left_type)
this.addCoercion(node.right, right_type)
this.result = Any
}
else
this.result = Integer
}
else if (op === '|' || op === '^' || op === '&' || op === '<<' || op === '>>' || op === '>>>') {
this.assert(left_type === Integer && right_type === Integer,
this.invalidOperandsMessage(op, left_type, right_type), node)
this.result = Integer
Expand Down Expand Up @@ -722,9 +733,17 @@ export default class TypeChecker<Info extends NameInfo> extends visitor.NodeVisi
this.addCoercion(node.right, right_type)
}
}
else if (op === '%=') {
this.assert((left_type === Integer || left_type === Any) && (right_type === Integer || right_type === Any),
'invalid operands to %=. They must be integer or any', node)
if (left_type === Any || right_type === Any) {
this.addCoercion(node.left, left_type)
this.addCoercion(node.right, right_type)
}
}
else if (op === '|=' || op === '^=' || op === '&=' || op === '%=' || op === '<<=' || op === '>>=')
this.assert(left_type === Integer && right_type === Integer,
this.invalidOperandsMessage(op, left_type, right_type), node)
this.invalidOperandsMessage(op, left_type, right_type), node)
else // '||=', '&&=', '>>>=', '**=', op === '??='
this.assert(false, `not supported operator '${op}'`, node)

Expand Down
100 changes: 100 additions & 0 deletions server/tests/transpiler/code-generator/code-generator2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,103 @@ print(barbar(7))
const imp = new Importer(modules)
expect(importAndCompileAndRun(src, imp.importer(), imp.init(), imp.files(), imp.path)).toBe('8\n')
})

test('/ and /= operators', () => {
const src = `
let a = 239
let b = a / 13
print(b)
a /= 4
print(a)
`

expect(compileAndRun(src)).toBe('18\n59\n')

const src1 = `
let a = 239.3
let b = a / 13.2
print(b)
a /= 4.3
print(a)
`

expect(compileAndRun(src1)).toBe('18.128788\n55.651165\n')

const src2 = `
let a: any = 239
let b = a / 13
print(b)
let c: any = 13
let d = a / c
print(d)
let e = 239 / c
print(e)
let f = a /= 4
print(a)
print(f)
print(typeof f)
let i: integer = 239
let j = i /= c
print(i)
print(j)
print(typeof j)
`

expect(compileAndRun(src2)).toBe('18\n18\n18\n59\n59\nany\n18\n18\ninteger\n')

const src3 = `
let a: any = 239.3
let b = a / 13.2
print(b)
let c: any = 13.2
let d = a / c
print(d)
let e = 239.3 / c
print(e)
let f = a /= 4.7
print(a)
print(f)
print(typeof f)
let i: float = 239.3
let j = i /= c
print(i)
print(j)
print(typeof j)
`

expect(compileAndRun(src3)).toBe('18.128788\n18.128788\n18.128788\n50.914898\n50.914898\nany\n18.128788\n18.128788\nfloat\n')
})

test('% and %= operators', () => {
const src = `
let a = 239
let b = a % 13
print(b)
a %= 4
print(a)
`

expect(compileAndRun(src)).toBe('5\n3\n')

const src2 = `
let a: any = 239
let b = a % 13
print(b)
let c: any = 13
let d = a % c
print(d)
let e = 239 % c
print(e)
let f = a %= 4
print(a)
print(f)
print(typeof f)
let i: integer = 239
let j = i %= c
print(i)
print(j)
print(typeof j)
`

expect(compileAndRun(src2)).toBe('5\n5\n5\n3\n3\nany\n5\n5\ninteger\n')
})

0 comments on commit 5777704

Please sign in to comment.