Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[V-125] Lowercase string type #54

Merged
merged 2 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/__tests__/compiler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ describe("E2E Compiler Pipeline", () => {
});

const readString = (ref: Object, instance: WebAssembly.Instance) => {
const newStringReader = getWasmFn("new_string_reader", instance)!;
const newStringIterator = getWasmFn("new_string_iterator", instance)!;
const readNextChar = getWasmFn("read_next_char", instance)!;
const reader = newStringReader(ref);
const reader = newStringIterator(ref);

let str = "";
while (true) {
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/fixtures/e2e-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn main()
`;

export const kitchenSink = `
pub use std::string::all
pub use std::string_lib::all

obj Vec {
x: i32,
Expand Down Expand Up @@ -232,7 +232,7 @@ pub fn test19() -> i32
if i == 5 then: break
x

pub fn test20() -> String
pub fn test20() -> string
"Hello, world!" + " " + "This is a test."
`;

Expand Down
21 changes: 20 additions & 1 deletion src/assembler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { initExtensionHelpers } from "./assembler/extension-helpers.js";
import { returnCall } from "./assembler/return-call.js";
import { Float } from "./syntax-objects/float.js";
import { initFieldLookupHelpers } from "./assembler/field-lookup-helpers.js";
import { List } from "./syntax-objects/list.js";
import { StringLiteral } from "./syntax-objects/string-literal.js";

export const assemble = (ast: Expr) => {
const mod = new binaryen.Module();
Expand Down Expand Up @@ -62,6 +62,7 @@ export const compileExpression = (opts: CompileExprOpts): number => {
if (expr.isBlock()) return compileBlock({ ...opts, expr, isReturnExpr });
if (expr.isMatch()) return compileMatch({ ...opts, expr, isReturnExpr });
if (expr.isInt()) return compileInt({ ...opts, expr });
if (expr.isStringLiteral()) return compileStringLiteral({ ...opts, expr });
if (expr.isFloat()) return compileFloat({ ...opts, expr });
if (expr.isIdentifier()) return compileIdentifier({ ...opts, expr });
if (expr.isFn()) return compileFunction({ ...opts, expr });
Expand All @@ -84,6 +85,15 @@ export const compileExpression = (opts: CompileExprOpts): number => {
);
};

const compileStringLiteral = (opts: CompileExprOpts<StringLiteral>) => {
const { expr, mod } = opts;
return gc.arrayNewFixed(
mod,
binaryenTypeToHeapType(getI32ArrayType(opts.mod)),
expr.value.split("").map((char) => mod.i32.const(char.charCodeAt(0)))
);
};

const compileInt = (opts: CompileExprOpts<Int>) => {
const val = opts.expr.value;
if (typeof val === "number") {
Expand Down Expand Up @@ -550,6 +560,8 @@ export const mapBinaryenType = (
if (isPrimitiveId(type, "i64")) return binaryen.i64;
if (isPrimitiveId(type, "f64")) return binaryen.f64;
if (isPrimitiveId(type, "voyd")) return binaryen.none;
if (isPrimitiveId(type, "string")) return getI32ArrayType(opts.mod);

if (type.isObjectType()) return buildObjectType(opts, type);
if (type.isUnionType()) return buildUnionType(opts, type);
if (type.isFixedArrayType()) return buildFixedArrayType(opts, type);
Expand Down Expand Up @@ -687,3 +699,10 @@ const compileObjMemberAccess = (opts: CompileExprOpts<Call>) => {
exprRef: objValue,
});
};

let i32ArrayType: TypeRef | undefined = undefined;
const getI32ArrayType = (mod: binaryen.Module) => {
if (i32ArrayType) return i32ArrayType;
i32ArrayType = gc.defineArrayType(mod, binaryen.i32, true);
return i32ArrayType;
};
4 changes: 2 additions & 2 deletions src/semantics/__tests__/__snapshots__/modules.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ exports[`module registration 1`] = `
[
"exports",
[
"src#373",
"std#402",
"src#377",
"std#406",
],
],
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ exports[`regular macro expansion 1`] = `
[
"exports",
[
"std#729",
"std#733",
],
],
[
Expand Down Expand Up @@ -47,7 +47,7 @@ exports[`regular macro expansion 1`] = `
],
[
"regular-macro",
"\`#758",
"\`#762",
[
"parameters",
],
Expand All @@ -68,7 +68,7 @@ exports[`regular macro expansion 1`] = `
],
[
"regular-macro",
"let#805",
"let#809",
[
"parameters",
],
Expand Down Expand Up @@ -121,7 +121,7 @@ exports[`regular macro expansion 1`] = `
],
[
"regular-macro",
"fn#1408",
"fn#1412",
[
"parameters",
],
Expand Down
4 changes: 3 additions & 1 deletion src/semantics/check-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ export const checkIf = (call: Call) => {

// Until unions are supported, throw an error when types don't match
if (!typesAreCompatible(thenType, elseType)) {
throw new Error("If condition clauses do not return same type");
throw new Error(
`If condition clauses do not return same type at ${call.location}`
);
}

call.type = thenType;
Expand Down
21 changes: 0 additions & 21 deletions src/semantics/init-entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
nop,
UnionType,
IntersectionType,
StringLiteral,
} from "../syntax-objects/index.js";
import { Match, MatchCase } from "../syntax-objects/match.js";
import { SemanticProcessor } from "./types.js";
Expand All @@ -25,8 +24,6 @@ export const initEntities: SemanticProcessor = (expr) => {
return expr.applyMap(initEntities);
}

if (expr.isStringLiteral()) return initStringLiteral(expr);

if (!expr.isList()) return expr;

if (expr.calls("define_function")) {
Expand Down Expand Up @@ -524,21 +521,3 @@ const initImpl = (impl: List): Implementation => {
/** Expects ["generics", ...Identifiers] */
const extractTypeParams = (list: List) =>
list.sliceAsArray(1).flatMap((p) => (p.isIdentifier() ? p : []));

const initStringLiteral = (str: StringLiteral) =>
initEntities(
new List({
...str.metadata,
value: [
"String",
[
"object",
[
":",
"chars",
["FixedArray", ...str.value.split("").map((c) => c.charCodeAt(0))],
],
],
],
})
);
13 changes: 12 additions & 1 deletion src/semantics/init-primitive-types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { i32, f32, i64, f64, bool, dVoid } from "../syntax-objects/types.js";
import {
i32,
f32,
i64,
f64,
bool,
dVoid,
dVoyd,
voydString,
} from "../syntax-objects/types.js";
import { voydBaseObject } from "../syntax-objects/types.js";
import { SemanticProcessor } from "./types.js";

Expand All @@ -10,6 +19,8 @@ export const initPrimitiveTypes: SemanticProcessor = (expr) => {
expr.registerExport(f64);
expr.registerExport(bool);
expr.registerExport(dVoid);
expr.registerExport(dVoyd);
expr.registerExport(voydString);
expr.registerExport(voydBaseObject);
return expr;
};
11 changes: 10 additions & 1 deletion src/semantics/resolution/get-expr-type.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { Expr } from "../../syntax-objects/expr.js";
import { Call, Identifier } from "../../syntax-objects/index.js";
import { Type, i32, f32, bool, i64, f64 } from "../../syntax-objects/types.js";
import {
Type,
i32,
f32,
bool,
i64,
f64,
voydString,
} from "../../syntax-objects/types.js";
import { resolveCall } from "./resolve-call.js";

export const getExprType = (expr?: Expr): Type | undefined => {
if (!expr) return;
if (expr.isInt()) return typeof expr.value === "number" ? i32 : i64;
if (expr.isFloat()) return typeof expr.value === "number" ? f32 : f64;
if (expr.isStringLiteral()) return voydString;
if (expr.isBool()) return bool;
if (expr.isIdentifier()) return getIdentifierType(expr);
if (expr.isCall()) return resolveCall(expr)?.type;
Expand Down
9 changes: 9 additions & 0 deletions src/semantics/resolution/resolve-call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const resolveCall = (call: Call): Call => {
if (call.calls(":")) return resolveLabeledArg(call);
if (call.calls("while")) return resolveWhile(call);
if (call.calls("FixedArray")) return resolveFixedArray(call);
if (call.calls("binaryen")) return resolveBinaryen(call);
call.args = call.args.map(resolveEntities);

const memberAccessCall = getMemberAccessCall(call);
Expand Down Expand Up @@ -162,3 +163,11 @@ export const resolveWhile = (call: Call) => {
call.type = dVoid;
return call;
};

export const resolveBinaryen = (call: Call) => {
call.args = call.args.map(resolveEntities);
const type = call.optionalLabeledArgAt(3);
if (!type) return call;
call.type = getExprType(type);
return call;
};
16 changes: 11 additions & 5 deletions src/syntax-objects/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,6 @@ export class FixedArrayType extends BaseType {

export class FnType extends BaseType {
readonly kindOfType = "fn";
readonly size = 0;
readonly parameters: Parameter[];
readonly returnType: Type;

Expand Down Expand Up @@ -343,8 +342,14 @@ export class FnType extends BaseType {
}
}

export type StackType = NumericType | ReferenceType;
export type Primitive = NumericType | ReferenceType | "voyd" | "bool";
export type Primitive =
| NumericType
| ReferenceType
| "void"
| "voyd"
| "bool"
| "string";

export type NumericType = "i32" | "f32" | "i64" | "f64";
export type ReferenceType = "funcref" | "externref";

Expand All @@ -353,9 +358,10 @@ export const f32 = PrimitiveType.from("f32");
export const i64 = PrimitiveType.from("i64");
export const f64 = PrimitiveType.from("f64");
export const bool = PrimitiveType.from("bool");
export const dVoid = PrimitiveType.from("voyd");
export const dVoid = PrimitiveType.from("void");
export const dVoyd = PrimitiveType.from("voyd");
export const voydString = PrimitiveType.from("string");
export const voydBaseObject = new ObjectType({
name: "Object",
value: [],
});
export const CDT_ADDRESS_TYPE = i32;
39 changes: 17 additions & 22 deletions std/array.voyd
Original file line number Diff line number Diff line change
@@ -1,42 +1,37 @@
use std::macros::all

macro binaryen_gc_call(func, args)
` binaryen func: $func namespace: gc args: $args

macro bin_type_to_heap_type(type)
// binaryen_gc_call(modBinaryenTypeToHeapType, ` [BnrType<($type)>])
` binaryen
func: modBinaryenTypeToHeapType
namespace: gc
args: [BnrType<($type)>]

pub fn new_fixed_array<T>(size: i32) -> FixedArray<T>
binaryen_gc_call(arrayNew, [bin_type_to_heap_type(FixedArray<T>), size])
binaryen_gc_call(
arrayNew,
[bin_type_to_heap_type(FixedArray<T>), size],
FixedArray<T>
)

pub fn get<T>(arr: FixedArray<T>, index: i32) -> T
binaryen_gc_call(
arrayGet,
[arr, index, BnrType<T>, BnrConst(false)]
[arr, index, BnrType<T>, BnrConst(false)],
T
)

pub fn set<T>(arr: FixedArray<T>, index: i32, value: T) -> FixedArray<T>
binaryen_gc_call(arraySet, [arr, index, value])
binaryen_gc_call(arraySet, [arr, index, value], FixedArray<T>)
arr

pub fn copy<T>(destArr: FixedArray<T>, opts: {
pub fn copy<T>(dest_array: FixedArray<T>, opts: {
from: FixedArray<T>,
toIndex: i32,
fromIndex: i32,
to_index: i32,
from_index: i32,
count: i32
}) -> FixedArray<T>
binaryen_gc_call(arrayCopy, [
destArr,
opts.toIndex,
dest_array,
opts.to_index,
opts.from,
opts.fromIndex,
opts.from_index,
opts.count
])
destArr
], FixedArray<T>)
dest_array

pub fn length<T>(arr: FixedArray<T>) -> i32
binaryen_gc_call(arrayLen, [arr])
binaryen_gc_call(arrayLen, [arr], i32)
4 changes: 2 additions & 2 deletions std/index.voyd
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ pub mod macros
pub mod macros::all
pub mod operators::all
pub mod utils::all
pub mod string::all
pub mod string_lib::all
pub mod array::all
pub mod string
pub mod string_lib
10 changes: 10 additions & 0 deletions std/macros.voyd
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,13 @@ pub macro fn()
(return_type $@return_type),
$fn_body
)

pub macro binaryen_gc_call(func, args, return_type)
` binaryen func: $func namespace: gc args: $args return_type: $return_type

pub macro bin_type_to_heap_type(type)
// binaryen_gc_call(modBinaryenTypeToHeapType, ` [BnrType<($type)>])
` binaryen
func: modBinaryenTypeToHeapType
namespace: gc
args: [BnrType<($type)>]
Loading