This commit is contained in:
parent
a42917b485
commit
4f9ea23d84
@ -94,6 +94,8 @@ export class Node {
|
||||
return visit();
|
||||
case "IntExpr":
|
||||
return visit();
|
||||
case "StrExpr":
|
||||
return visit();
|
||||
case "ArrayExpr":
|
||||
return visit(...k.values);
|
||||
case "IndexExpr":
|
||||
@ -141,6 +143,7 @@ export type NodeKind =
|
||||
| { tag: "Param"; ident: string; ty: Node | null }
|
||||
| { tag: "IdentExpr"; ident: string }
|
||||
| { tag: "IntExpr"; value: number }
|
||||
| { tag: "StrExpr"; value: string }
|
||||
| { tag: "ArrayExpr"; values: Node[] }
|
||||
| { tag: "IndexExpr"; value: Node; arg: Node }
|
||||
| { tag: "CallExpr"; value: Node; args: Node[] }
|
||||
|
||||
@ -146,6 +146,10 @@ class Checker {
|
||||
return Ty.Int;
|
||||
}
|
||||
|
||||
if (node.is("StrExpr")) {
|
||||
return Ty.create("Ptr", { ty: Ty.Str });
|
||||
}
|
||||
|
||||
if (node.is("ArrayExpr")) {
|
||||
let ty: Ty | null = null;
|
||||
for (const value of node.kind.values) {
|
||||
@ -179,6 +183,12 @@ class Checker {
|
||||
) {
|
||||
return Ty.create("Slice", { ty: exprTy.kind.ty });
|
||||
}
|
||||
if (
|
||||
exprTy.is("Str") &&
|
||||
argTy.compatibleWith(Ty.Int)
|
||||
) {
|
||||
return Ty.Int;
|
||||
}
|
||||
this.error(
|
||||
node.loc,
|
||||
`cannot use index operator on '${exprTy.pretty()}' with '${argTy.pretty()}'`,
|
||||
@ -264,6 +274,8 @@ class Checker {
|
||||
return Ty.Int;
|
||||
case "bool":
|
||||
return Ty.Bool;
|
||||
case "str":
|
||||
return Ty.Str;
|
||||
default:
|
||||
this.error(node.loc, `unknown type '${node.kind.ident}'`);
|
||||
}
|
||||
@ -310,9 +322,36 @@ class Checker {
|
||||
private checkCall(node: ast.NodeWithKind<"CallExpr">): Ty {
|
||||
if (node.kind.value.is("IdentExpr")) {
|
||||
const sym = this.syms.get(node.kind.value);
|
||||
if (sym && sym.tag === "Builtin") {
|
||||
if (sym.id === "debug_print") {
|
||||
const _argTys = node.kind.args
|
||||
if (sym.tag === "Builtin") {
|
||||
if (sym.id === "len") {
|
||||
if (node.kind.args.length !== 1) {
|
||||
this.reportArgsIncorrectAmount(
|
||||
node,
|
||||
node.kind.args.length,
|
||||
0,
|
||||
null,
|
||||
);
|
||||
}
|
||||
const argTy = this.tys.expr(node.kind.args[0]);
|
||||
if (
|
||||
!(argTy.is("Array") ||
|
||||
argTy.is("Ptr") &&
|
||||
(argTy.kind.ty.is("Array") ||
|
||||
argTy.kind.ty.is("Slice") ||
|
||||
argTy.kind.ty.is("Str")))
|
||||
) {
|
||||
this.reportArgTypeNotCompatible(
|
||||
node,
|
||||
[argTy],
|
||||
[Ty.Error],
|
||||
null,
|
||||
0,
|
||||
);
|
||||
}
|
||||
return Ty.Int;
|
||||
}
|
||||
if (sym.id === "print") {
|
||||
void node.kind.args
|
||||
.map((arg) => this.tys.expr(arg));
|
||||
return Ty.Void;
|
||||
}
|
||||
@ -339,11 +378,38 @@ class Checker {
|
||||
.map((arg) => this.tys.expr(arg));
|
||||
const params = callableTy.kind.params;
|
||||
if (args.length !== params.length) {
|
||||
this.reportArgsIncorrectAmount(
|
||||
node,
|
||||
args.length,
|
||||
params.length,
|
||||
calleeTy,
|
||||
);
|
||||
}
|
||||
for (const i of args.keys()) {
|
||||
if (!args[i].compatibleWith(params[i])) {
|
||||
this.reportArgTypeNotCompatible(
|
||||
node,
|
||||
args,
|
||||
params,
|
||||
calleeTy,
|
||||
i,
|
||||
);
|
||||
}
|
||||
}
|
||||
return callableTy.kind.retTy;
|
||||
}
|
||||
|
||||
private reportArgsIncorrectAmount(
|
||||
node: ast.NodeWithKind<"CallExpr">,
|
||||
argsLength: number,
|
||||
paramsLength: number,
|
||||
calleeTy: Ty | null,
|
||||
): never {
|
||||
this.error(
|
||||
node.loc,
|
||||
`incorrect amount of arguments. got ${args.length} expected ${params.length}`,
|
||||
`incorrect amount of arguments. got ${argsLength} expected ${paramsLength}`,
|
||||
);
|
||||
if (calleeTy.is("FnStmt")) {
|
||||
if (calleeTy?.is("FnStmt")) {
|
||||
this.info(
|
||||
calleeTy.kind.stmt.loc,
|
||||
"function defined here",
|
||||
@ -351,15 +417,21 @@ class Checker {
|
||||
}
|
||||
this.fail();
|
||||
}
|
||||
for (const i of args.keys()) {
|
||||
if (!args[i].compatibleWith(params[i])) {
|
||||
|
||||
private reportArgTypeNotCompatible(
|
||||
node: ast.NodeWithKind<"CallExpr">,
|
||||
args: Ty[],
|
||||
params: Ty[],
|
||||
calleeTy: Ty | null,
|
||||
i: number,
|
||||
): never {
|
||||
this.error(
|
||||
node.kind.args[i].loc,
|
||||
`type '${args[i].pretty()}' not compatible with type '${
|
||||
params[i].pretty()
|
||||
}', for argument ${i}`,
|
||||
);
|
||||
if (calleeTy.is("FnStmt")) {
|
||||
if (calleeTy?.is("FnStmt")) {
|
||||
this.info(
|
||||
calleeTy.kind.stmt.kind.params[i].loc,
|
||||
`parameter '${
|
||||
@ -370,9 +442,6 @@ class Checker {
|
||||
}
|
||||
this.fail();
|
||||
}
|
||||
}
|
||||
return callableTy.kind.retTy;
|
||||
}
|
||||
|
||||
private assertCompatible(left: Ty, right: Ty, loc: Loc): void {
|
||||
if (!left.compatibleWith(right)) {
|
||||
|
||||
@ -289,6 +289,10 @@ export class Parser {
|
||||
const value = Number(this.current.value);
|
||||
this.step();
|
||||
return ast.Node.create(loc, "IntExpr", { value });
|
||||
} else if (this.test("str")) {
|
||||
const value = this.current.value;
|
||||
this.step();
|
||||
return ast.Node.create(loc, "StrExpr", { value });
|
||||
} else if (this.eat("(")) {
|
||||
const expr = this.parseExpr();
|
||||
this.mustEat(")");
|
||||
@ -414,6 +418,25 @@ export function tokenize(text: string, reporter: FileReporter): Tok[] {
|
||||
.add(/0|(?:[1-9][0-9]*)/, (loc, value) => {
|
||||
return { type: "int", value, loc };
|
||||
})
|
||||
.add(/"(?:[^\\"]|\\.)*"/, (loc, literal) => {
|
||||
let i = 1;
|
||||
let value = "";
|
||||
while (i < literal.length - 1) {
|
||||
if (literal[i] === "\\") {
|
||||
i += 1;
|
||||
value += {
|
||||
"0": "\0",
|
||||
"t": "\t",
|
||||
"r": "\r",
|
||||
"n": "\n",
|
||||
}[literal[i]] ?? literal[i];
|
||||
} else {
|
||||
value += literal[i];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return { type: "str", value, loc };
|
||||
})
|
||||
.add(/./, (loc, value) => {
|
||||
const escapedChar = JSON.stringify(value[0]).slice(1, -1);
|
||||
reporter.error(loc, `illegal character '${escapedChar}'`);
|
||||
|
||||
@ -113,7 +113,8 @@ class ResolverSyms {
|
||||
static root(): ResolverSyms {
|
||||
return new ResolverSyms(
|
||||
new Map([
|
||||
["debug_print", { tag: "Builtin", id: "debug_print" }],
|
||||
["len", { tag: "Builtin", id: "len" }],
|
||||
["print", { tag: "Builtin", id: "print" }],
|
||||
]),
|
||||
null,
|
||||
);
|
||||
|
||||
14
src/main.ts
14
src/main.ts
@ -46,7 +46,8 @@ function printMirFn(fn: mir.Fn) {
|
||||
.split("\n")
|
||||
.map<[string, string[]]>((line) => [line, []])
|
||||
.map<[string, string[]]>(([line, colors]) => {
|
||||
line = line.replace(/%(\d+)/g, "__%$1__");
|
||||
line = line.replace(/%\d+/g, "__$&__");
|
||||
line = line.replace(/"(?:[^"\\]|\\.)*"/g, "__$&__");
|
||||
if (/^\s*__%\d+__ \(.*?\) =/.test(line)) {
|
||||
line = line.replace(
|
||||
/__%(\d+)__ \((.*?)\) =/g,
|
||||
@ -56,15 +57,22 @@ function printMirFn(fn: mir.Fn) {
|
||||
}
|
||||
if (/[A-Z][a-zA-Z]+/.test(line)) {
|
||||
line = line.replace(/([A-Z][a-zA-Z]+)/, "%c$1%c");
|
||||
colors.push("color: red;", "");
|
||||
colors.push("color: red; font-weight: bold;", "");
|
||||
}
|
||||
if (/\bptr\b/.test(line)) {
|
||||
line = line.replace(/\b(ptr)\b/, "%c$1%c");
|
||||
colors.push("color: gray;", "");
|
||||
}
|
||||
while (/__%\d+__/.test(line)) {
|
||||
while (true) {
|
||||
if (/__%\d+__/.test(line)) {
|
||||
line = line.replace(/__%(\d+)__/, "%c%$1%c");
|
||||
colors.push("color: lightblue;", "");
|
||||
} else if (/__"(?:[^"\\]|\\.)*"__/.test(line)) {
|
||||
line = line.replace(/__("(?:[^"\\]|\\.)*")__/, "%c$1%c");
|
||||
colors.push("color: green;", "");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [line, colors];
|
||||
|
||||
@ -221,9 +221,7 @@ class FnLowerer {
|
||||
const valueTy = this.tys.place(value);
|
||||
const arg = place.kind.arg;
|
||||
const argTy = this.tys.expr(arg);
|
||||
if (!valueTy.is("Array") && !valueTy.is("Slice")) {
|
||||
throw new Error();
|
||||
}
|
||||
if (valueTy.is("Array") || valueTy.is("Slice")) {
|
||||
const valueInst = this.lowerPlace(place.kind.value);
|
||||
if (argTy.is("Int")) {
|
||||
const argInst = this.lowerExpr(arg);
|
||||
@ -249,6 +247,18 @@ class FnLowerer {
|
||||
{ value: valueInst, begin, end },
|
||||
);
|
||||
}
|
||||
}
|
||||
if (valueTy.is("Str")) {
|
||||
const valueInst = this.lowerPlace(place.kind.value);
|
||||
if (argTy.is("Int")) {
|
||||
const argInst = this.lowerExpr(arg);
|
||||
return this.pushInst(
|
||||
Ty.create("Ptr", { ty: Ty.Int }),
|
||||
"GetElemPtr",
|
||||
{ base: valueInst, offset: argInst },
|
||||
);
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`${place.kind.tag} with arg ${argTy.pretty()} not handled`,
|
||||
);
|
||||
@ -282,7 +292,10 @@ class FnLowerer {
|
||||
throw new Error(`'${sym.tag}' not handled`);
|
||||
}
|
||||
if (expr.is("IntExpr")) {
|
||||
return this.pushInst(Ty.Int, "Int", { value: expr.kind.value });
|
||||
return this.pushInst(ty, "Int", { value: expr.kind.value });
|
||||
}
|
||||
if (expr.is("StrExpr")) {
|
||||
return this.pushInst(ty, "Str", { value: expr.kind.value });
|
||||
}
|
||||
if (expr.is("ArrayExpr")) {
|
||||
const ty = this.tys.expr(expr);
|
||||
@ -295,14 +308,16 @@ class FnLowerer {
|
||||
return this.pushInst(ty, "Load", { source });
|
||||
}
|
||||
if (expr.is("CallExpr")) {
|
||||
const ty = this.tys.expr(expr);
|
||||
const args = expr.kind.args
|
||||
.map((arg) => this.lowerExpr(arg));
|
||||
|
||||
if (expr.kind.value.is("IdentExpr")) {
|
||||
const sym = this.syms.get(expr.kind.value);
|
||||
if (sym.tag === "Builtin") {
|
||||
if (sym.id === "debug_print") {
|
||||
if (sym.id === "len") {
|
||||
return this.pushInst(ty, "Len", { source: args[0] });
|
||||
}
|
||||
if (sym.id === "print") {
|
||||
return this.pushInst(ty, "DebugPrint", { args });
|
||||
}
|
||||
throw new Error(`builtin '${sym.id}' not handled`);
|
||||
@ -316,24 +331,23 @@ class FnLowerer {
|
||||
return this.lowerUnaryExpr(expr);
|
||||
}
|
||||
if (expr.is("BinaryExpr")) {
|
||||
const resultTy = this.tys.expr(expr);
|
||||
const leftTy = this.tys.expr(expr.kind.left);
|
||||
const rightTy = this.tys.expr(expr.kind.right);
|
||||
const binaryOp = binaryOpPatterns
|
||||
.find((pat) =>
|
||||
expr.kind.op === pat.op &&
|
||||
resultTy.compatibleWith(pat.result) &&
|
||||
ty.compatibleWith(pat.result) &&
|
||||
leftTy.compatibleWith(pat.left ?? pat.result) &&
|
||||
rightTy.compatibleWith(pat.right ?? pat.left ?? pat.result)
|
||||
);
|
||||
if (!binaryOp) {
|
||||
throw new Error(
|
||||
`'${expr.kind.op}' with '${resultTy.pretty()}' not handled`,
|
||||
`'${expr.kind.op}' with '${ty.pretty()}' not handled`,
|
||||
);
|
||||
}
|
||||
const left = this.lowerExpr(expr.kind.left);
|
||||
const right = this.lowerExpr(expr.kind.right);
|
||||
return this.pushInst(resultTy, binaryOp.tag, { left, right });
|
||||
return this.pushInst(ty, binaryOp.tag, { left, right });
|
||||
}
|
||||
throw new Error(`'${expr.kind.tag}' not handled`);
|
||||
}
|
||||
|
||||
@ -121,6 +121,8 @@ export class Inst {
|
||||
case "Int":
|
||||
case "Bool":
|
||||
return `${k.value}`;
|
||||
case "Str":
|
||||
return `${JSON.stringify(k.value)}`;
|
||||
case "Array":
|
||||
return `[${k.values.map(r).join(", ")}]`;
|
||||
case "Fn":
|
||||
@ -169,6 +171,8 @@ export class Inst {
|
||||
case "Div":
|
||||
case "Rem":
|
||||
return `${r(k.left)} ${r(k.right)}`;
|
||||
case "Len":
|
||||
return `${r(k.source)}`;
|
||||
case "DebugPrint":
|
||||
return `${k.args.map(r).join(", ")}`;
|
||||
}
|
||||
@ -181,6 +185,7 @@ export type InstKind =
|
||||
| { tag: "Void" }
|
||||
| { tag: "Int"; value: number }
|
||||
| { tag: "Bool"; value: boolean }
|
||||
| { tag: "Str"; value: string }
|
||||
| { tag: "Array"; values: Inst[] }
|
||||
| { tag: "Fn"; fn: Fn }
|
||||
| { tag: "Param"; idx: number }
|
||||
@ -196,6 +201,7 @@ export type InstKind =
|
||||
| { tag: "Not"; source: Inst }
|
||||
| { tag: "Negate"; source: Inst }
|
||||
| { tag: BinaryOp; left: Inst; right: Inst }
|
||||
| { tag: "Len"; source: Inst }
|
||||
| { tag: "DebugPrint"; args: Inst[] };
|
||||
|
||||
export type BinaryOp =
|
||||
|
||||
@ -31,6 +31,7 @@ export class FnInterpreter {
|
||||
case "Void":
|
||||
case "Int":
|
||||
case "Bool":
|
||||
case "Str":
|
||||
this.regs.set(inst, new Val(k));
|
||||
break;
|
||||
case "Array":
|
||||
@ -59,7 +60,6 @@ export class FnInterpreter {
|
||||
if (base.kind.tag === "Ptr") {
|
||||
const array = base.kind.value;
|
||||
if (array.kind.tag !== "Array") {
|
||||
console.log({ array });
|
||||
throw new Error();
|
||||
}
|
||||
if (
|
||||
@ -91,6 +91,22 @@ export class FnInterpreter {
|
||||
mutable: base.kind.mutable,
|
||||
}),
|
||||
);
|
||||
} else if (base.kind.tag === "Str") {
|
||||
const str = base.kind.value;
|
||||
if (
|
||||
offset.kind.value < 0 ||
|
||||
offset.kind.value >= str.length
|
||||
) {
|
||||
throw new Error();
|
||||
}
|
||||
this.regs.set(
|
||||
inst,
|
||||
new Val({
|
||||
tag: "StrElemPtr",
|
||||
value: str,
|
||||
idx: offset.kind.value,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
@ -172,8 +188,17 @@ export class FnInterpreter {
|
||||
inst,
|
||||
source.kind.values[source.kind.idx],
|
||||
);
|
||||
} else if (source.kind.tag === "StrElemPtr") {
|
||||
this.regs.set(
|
||||
inst,
|
||||
new Val({
|
||||
tag: "Int",
|
||||
value: source.kind.value.charCodeAt(
|
||||
source.kind.idx,
|
||||
),
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
console.log({ source });
|
||||
throw new Error();
|
||||
}
|
||||
break;
|
||||
@ -248,6 +273,23 @@ export class FnInterpreter {
|
||||
case "Rem":
|
||||
this.evalBinaryOp(inst, k);
|
||||
break;
|
||||
case "Len": {
|
||||
const source = this.regs.get(k.source)!;
|
||||
if (source.kind.tag === "Array") {
|
||||
throw new Error();
|
||||
} else if (source.kind.tag === "Str") {
|
||||
this.regs.set(
|
||||
inst,
|
||||
new Val({
|
||||
tag: "Int",
|
||||
value: source.kind.value.length,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "DebugPrint":
|
||||
console.log(
|
||||
k.args
|
||||
@ -335,8 +377,11 @@ class Val {
|
||||
case "Int":
|
||||
case "Bool":
|
||||
return `${k.value}`;
|
||||
case "Str":
|
||||
return k.value;
|
||||
case "Ptr":
|
||||
case "ArrayElemPtr":
|
||||
case "StrElemPtr":
|
||||
return `<pointer>`;
|
||||
case "ArraySlice":
|
||||
return `[${
|
||||
@ -361,6 +406,9 @@ type ValKind =
|
||||
| { tag: "Void" }
|
||||
| { tag: "Int"; value: number }
|
||||
| { tag: "Bool"; value: boolean }
|
||||
| { tag: "Str"; value: string }
|
||||
| { tag: "Array"; values: Val[] }
|
||||
| { tag: "Fn"; fn: mir.Fn }
|
||||
| { tag: "Ptr"; mutable: boolean; value: Val }
|
||||
| { tag: "ArrayElemPtr"; mutable: boolean; values: Val[]; idx: number }
|
||||
| {
|
||||
@ -370,5 +418,4 @@ type ValKind =
|
||||
begin: number;
|
||||
end: number;
|
||||
}
|
||||
| { tag: "Array"; values: Val[] }
|
||||
| { tag: "Fn"; fn: mir.Fn };
|
||||
| { tag: "StrElemPtr"; value: string; idx: number };
|
||||
|
||||
@ -25,6 +25,7 @@ export class Ty {
|
||||
static Void = Ty.create("Void", {});
|
||||
static Int = Ty.create("Int", {});
|
||||
static Bool = Ty.create("Bool", {});
|
||||
static Str = Ty.create("Str", {});
|
||||
|
||||
private internHash(): string {
|
||||
return JSON.stringify(this.kind);
|
||||
@ -59,6 +60,9 @@ export class Ty {
|
||||
if (this.is("Bool")) {
|
||||
return other.is("Bool");
|
||||
}
|
||||
if (this.is("Str")) {
|
||||
return other.is("Str");
|
||||
}
|
||||
if (this.is("Ptr")) {
|
||||
if (!other.is("Ptr")) {
|
||||
return false;
|
||||
@ -123,7 +127,7 @@ export class Ty {
|
||||
}
|
||||
|
||||
isSized(): boolean {
|
||||
if (this.is("Slice")) {
|
||||
if (this.is("Slice") || this.is("Str")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -139,6 +143,8 @@ export class Ty {
|
||||
return "int";
|
||||
case "Bool":
|
||||
return "bool";
|
||||
case "Str":
|
||||
return "str";
|
||||
case "Ptr":
|
||||
return `*${this.kind.ty.pretty()}`;
|
||||
case "PtrMut":
|
||||
@ -175,6 +181,7 @@ export type TyKind =
|
||||
| { tag: "Void" }
|
||||
| { tag: "Int" }
|
||||
| { tag: "Bool" }
|
||||
| { tag: "Str" }
|
||||
| { tag: "Ptr"; ty: Ty }
|
||||
| { tag: "PtrMut"; ty: Ty }
|
||||
| { tag: "Array"; ty: Ty; length: number }
|
||||
|
||||
@ -5,20 +5,20 @@ fn main()
|
||||
|
||||
let elem: int = array[0];
|
||||
// expect: 1
|
||||
debug_print(elem);
|
||||
print(elem);
|
||||
|
||||
let ptr_to_array: *[int; 3] = &array;
|
||||
// expect: 2
|
||||
debug_print(ptr_to_array.*[1]);
|
||||
print(ptr_to_array.*[1]);
|
||||
|
||||
let slice: *[int] = &array[..];
|
||||
// expect: 3
|
||||
debug_print(slice.*[2]);
|
||||
print(slice.*[2]);
|
||||
|
||||
let slice_mut: *mut [int] = &mut array[1..3];
|
||||
slice_mut.*[0] = 4;
|
||||
// expect: 4
|
||||
debug_print(array[1]);
|
||||
print(array[1]);
|
||||
}
|
||||
|
||||
// vim: syntax=rust commentstring=//\ %s
|
||||
|
||||
@ -4,6 +4,6 @@ fn main()
|
||||
{
|
||||
let v: int = 123;
|
||||
v = 456;
|
||||
debug_print(v);
|
||||
print(v);
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ fn main()
|
||||
a = 3;
|
||||
}
|
||||
|
||||
debug_print(a);
|
||||
print(a);
|
||||
|
||||
if false {
|
||||
a = 4;
|
||||
@ -21,5 +21,5 @@ fn main()
|
||||
a = 5;
|
||||
}
|
||||
|
||||
debug_print(a);
|
||||
print(a);
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ fn main()
|
||||
a = a + 1;
|
||||
}
|
||||
|
||||
debug_print(a);
|
||||
print(a);
|
||||
|
||||
while a < 10 {
|
||||
if a >= 8 {
|
||||
@ -18,5 +18,5 @@ fn main()
|
||||
a = a + 1;
|
||||
}
|
||||
|
||||
debug_print(a);
|
||||
print(a);
|
||||
}
|
||||
|
||||
@ -13,20 +13,20 @@ fn main()
|
||||
let a = 5;
|
||||
let b = 3;
|
||||
|
||||
debug_print(a + b);
|
||||
debug_print(a - b);
|
||||
debug_print(a * b);
|
||||
debug_print(a * b / 2);
|
||||
debug_print(a % b);
|
||||
debug_print(-a);
|
||||
print(a + b);
|
||||
print(a - b);
|
||||
print(a * b);
|
||||
print(a * b / 2);
|
||||
print(a % b);
|
||||
print(-a);
|
||||
|
||||
let c = false;
|
||||
|
||||
if not c {
|
||||
debug_print(123);
|
||||
print(123);
|
||||
}
|
||||
|
||||
debug_print(2 * 3 + 4);
|
||||
debug_print(2 * (3 + 4));
|
||||
print(2 * 3 + 4);
|
||||
print(2 * (3 + 4));
|
||||
}
|
||||
|
||||
|
||||
@ -9,21 +9,21 @@ fn main()
|
||||
let a = 1;
|
||||
let b: *int = &a;
|
||||
// expect: 1
|
||||
debug_print(*b);
|
||||
print(*b);
|
||||
|
||||
a = 2;
|
||||
// expect: 2
|
||||
debug_print(*b);
|
||||
print(*b);
|
||||
|
||||
let c: *mut int = &mut a;
|
||||
*c = 3;
|
||||
// expect: 3
|
||||
debug_print(a);
|
||||
print(a);
|
||||
// expect: 3
|
||||
debug_print(*c);
|
||||
print(*c);
|
||||
|
||||
change_to(&mut a, 4);
|
||||
// expect: 4
|
||||
debug_print(a);
|
||||
print(a);
|
||||
}
|
||||
|
||||
|
||||
14
tests/string.ethlang
Normal file
14
tests/string.ethlang
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
fn main()
|
||||
{
|
||||
let my_string: *str = "hello world";
|
||||
// expect: hello world
|
||||
print(my_string);
|
||||
// expect: 104
|
||||
print(my_string.*[0]);
|
||||
// expect: 11
|
||||
print(len(my_string));
|
||||
}
|
||||
|
||||
// vim: syntax=rust commentstring=//\ %s
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user