Skip to content

Commit

Permalink
add ** operator and stringifies bigint as string in JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
gfx committed Aug 9, 2024
1 parent ebce991 commit ad11123
Show file tree
Hide file tree
Showing 12 changed files with 62 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ This is a list of features in ECMA-262 that are planned or implemented ("[x]" do
* [ ] index access (`[0]` and `.["foo"]`)
* [ ] property access (`.foo`)
* [ ] `typeof` operator
* [ ] [WIP] arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`)
* [x] arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`)
* [x] bitwise operators (`~`, `&`, `|`, `^`, `<<`, `>>`, `>>>`)
* [ ] assignment operators (`=`, `+=`, `-=`, `*=`, `/=`, `%=`, `**=`, `<<=`, `>>=`, `>>>=`, `&=`, `|=`, `^=`)
* [x] comparison operators (`==`, `!=`, `===`, `!==`, `<`, `>`, `<=`, `>=`)
Expand Down
4 changes: 4 additions & 0 deletions spec/pow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const a = 1 ** 1;
export const b = 2 ** 32;
export const c = 2n ** 32n;
export const d = 2n ** 50n;
6 changes: 6 additions & 0 deletions spec/pow.ts.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"a": 1,
"b": 4294967296,
"c": "4294967296",
"d": "1125899906842624"
}
1 change: 1 addition & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub enum ExprEnum<'src> {
Mul(Box<Expression<'src>>, Box<Expression<'src>>),
Div(Box<Expression<'src>>, Box<Expression<'src>>),
Mod(Box<Expression<'src>>, Box<Expression<'src>>),
Pow(Box<Expression<'src>>, Box<Expression<'src>>),
BwOr(Box<Expression<'src>>, Box<Expression<'src>>),
BwAnd(Box<Expression<'src>>, Box<Expression<'src>>),
BwXor(Box<Expression<'src>>, Box<Expression<'src>>),
Expand Down
1 change: 1 addition & 0 deletions src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ impl Compiler {
ExprEnum::Mul(lhs, rhs) => self.bin_op(OpCode::Mul, lhs, rhs)?,
ExprEnum::Div(lhs, rhs) => self.bin_op(OpCode::Div, lhs, rhs)?,
ExprEnum::Mod(lhs, rhs) => self.bin_op(OpCode::Mod, lhs, rhs)?,
ExprEnum::Pow(lhs, rhs) => self.bin_op(OpCode::Pow, lhs, rhs)?,
ExprEnum::BwOr(lhs, rhs) => self.bin_op(OpCode::BwOr, lhs, rhs)?,
ExprEnum::BwAnd(lhs, rhs) => self.bin_op(OpCode::BwAnd, lhs, rhs)?,
ExprEnum::BwXor(lhs, rhs) => self.bin_op(OpCode::BwXor, lhs, rhs)?,
Expand Down
3 changes: 2 additions & 1 deletion src/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ pub enum OpCode {
Add,
Sub,
Mul,
Mod,
Div,
Mod,
Pow,
BwOr,
BwAnd,
BwXor,
Expand Down
20 changes: 10 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,12 @@ mod tests {
result,
json!(
{
"zero": 0,
"answer": 42,
"minus": -42,
"w_underscore": 1000000,
"i32_max": 2147483647i32,
"i64_max": 9223372036854775807i64
"zero": "0",
"answer": "42",
"minus": "-42",
"w_underscore": "1000000",
"i32_max": "2147483647",
"i64_max": "9223372036854775807"
}
)
);
Expand All @@ -320,7 +320,7 @@ mod tests {
"#,
)
.unwrap();
assert_eq!(result, json!({ "a": 43 }));
assert_eq!(result, json!({ "a": "43" }));
}

#[test]
Expand All @@ -331,7 +331,7 @@ mod tests {
"#,
)
.unwrap();
assert_eq!(result, json!({ "a": 41 }));
assert_eq!(result, json!({ "a": "41" }));
}

#[test]
Expand All @@ -342,7 +342,7 @@ mod tests {
"#,
)
.unwrap();
assert_eq!(result, json!({ "a": 84 }));
assert_eq!(result, json!({ "a": "84" }));
}

#[test]
Expand All @@ -353,7 +353,7 @@ mod tests {
"#,
)
.unwrap();
assert_eq!(result, json!({ "a": 14 }));
assert_eq!(result, json!({ "a": "14" }));
}

// TODO: literal types are not yet supported so the error message does not match TypeScript compiler's.
Expand Down
20 changes: 17 additions & 3 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ fn unary_op(i: Span) -> IResult<Span, Expression> {
}
}

fn factor(i: Span) -> IResult<Span, Expression> {
alt((
fn factor(input: Span) -> IResult<Span, Expression> {
let (i, expr) = alt((
undefined_literal,
null_literal,
true_literal,
Expand All @@ -134,7 +134,21 @@ fn factor(i: Span) -> IResult<Span, Expression> {
func_call,
ident,
parens,
))(i)
))(input)?;

let Ok((i, _)) = tag::<&str, Span, Error>("**")(i) else {
return Ok((i, expr));
};

let (i, rhs) = space_delimited(factor)(i)?;
Ok((
i,
Expression {
expr: ExprEnum::Pow(Box::new(expr), Box::new(rhs)),
span: input,
},
))

}

fn func_call(i: Span) -> IResult<Span, Expression> {
Expand Down
2 changes: 1 addition & 1 deletion src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl Serialize for Value {
serializer.serialize_f64(*value)
}
}
Self::Int(value) => serializer.serialize_i64(*value),
Self::Int(value) => serializer.serialize_str(value.to_string().as_str()),
Self::Str(value) => serializer.serialize_str(value),
Self::Array(value) => value.serialize(serializer),
Self::Object(value) => {
Expand Down
1 change: 1 addition & 0 deletions src/type_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ fn tc_expr<'src>(
Mul(lhs, rhs) => tc_bin_arithmetic_op(lhs, rhs, ctx, "*")?,
Div(lhs, rhs) => tc_bin_arithmetic_op(lhs, rhs, ctx, "/")?,
Mod(lhs, rhs) => tc_bin_arithmetic_op(lhs, rhs, ctx, "%")?,
Pow(lhs, rhs) => tc_bin_arithmetic_op(lhs, rhs, ctx, "**")?,
BwAnd(lhs, rhs) => tc_bin_arithmetic_op(lhs, rhs, ctx, "&")?,
BwOr(lhs, rhs) => tc_bin_arithmetic_op(lhs, rhs, ctx, "|")?,
BwXor(lhs, rhs) => tc_bin_arithmetic_op(lhs, rhs, ctx, "^")?,
Expand Down
11 changes: 11 additions & 0 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ fn bin_op_mod(lhs: &Value, rhs: &Value) -> Result<Value, Box<dyn Error>> {
}
}

fn bin_op_pow(lhs: &Value, rhs: &Value) -> Result<Value, Box<dyn Error>> {
match (lhs, rhs) {
(Value::Num(lhs), Value::Num(rhs)) => Ok(Value::Num(lhs.powf(*rhs))),
(Value::Int(lhs), Value::Int(rhs)) => Ok(Value::Int(
lhs.saturating_pow((*rhs).min(u32::MAX as i64) as u32),
)), // when overflowed, returns i64::MAX
_ => Err(err_bin_op("**", lhs, rhs)),
}
}

fn bin_op_bw_or(lhs: &Value, rhs: &Value) -> Result<Value, Box<dyn Error>> {
match (lhs, rhs) {
(Value::Num(lhs), Value::Num(rhs)) => Ok(Value::Num((*lhs as i32 | *rhs as i32) as f64)),
Expand Down Expand Up @@ -445,6 +455,7 @@ impl Vm {
OpCode::Mul => Self::interpret_bin_op(&mut self.top_mut()?.stack, bin_op_mul)?,
OpCode::Div => Self::interpret_bin_op(&mut self.top_mut()?.stack, bin_op_div)?,
OpCode::Mod => Self::interpret_bin_op(&mut self.top_mut()?.stack, bin_op_mod)?,
OpCode::Pow => Self::interpret_bin_op(&mut self.top_mut()?.stack, bin_op_pow)?,
OpCode::BwOr => Self::interpret_bin_op(&mut self.top_mut()?.stack, bin_op_bw_or)?,
OpCode::BwAnd => Self::interpret_bin_op(&mut self.top_mut()?.stack, bin_op_bw_and)?,
OpCode::BwXor => Self::interpret_bin_op(&mut self.top_mut()?.stack, bin_op_bw_xor)?,
Expand Down
8 changes: 7 additions & 1 deletion tiscript2json/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,11 @@ if (emitResult.emitSkipped) {
fs.renameSync(jsFile, mjsFile);
}
const result = await import(mjsFile);
console.log(JSON.stringify(result, null, 2));
console.log(JSON.stringify(result, (_key, value) => {
if (typeof value === "bigint") {
return value.toString();
} else {
return value;
}
}, 2));
}

0 comments on commit ad11123

Please sign in to comment.