Skip to content

Commit

Permalink
feat: 式に符号を使えるように (#852)
Browse files Browse the repository at this point in the history
* 式に負号を使えるように

* CHANGELOG
  • Loading branch information
takejohn authored Nov 15, 2024
1 parent 87e8edc commit 6118f9e
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 12 deletions.
16 changes: 15 additions & 1 deletion etc/aiscript.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ declare namespace Ast {
SubAssign,
Assign,
Expression,
Plus,
Minus,
Not,
Pow,
Mul,
Expand Down Expand Up @@ -298,7 +300,7 @@ type Exists = NodeBase & {
function expectAny(val: Value | null | undefined): asserts val is Value;

// @public (undocumented)
type Expression = If | Fn | Match | Block | Exists | Tmpl | Str | Num | Bool | Null | Obj | Arr | Not | Pow | Mul | Div | Rem | Add | Sub | Lt | Lteq | Gt | Gteq | Eq | Neq | And | Or | Identifier | Call | Index | Prop;
type Expression = If | Fn | Match | Block | Exists | Tmpl | Str | Num | Bool | Null | Obj | Arr | Plus | Minus | Not | Pow | Mul | Div | Rem | Add | Sub | Lt | Lteq | Gt | Gteq | Eq | Neq | And | Or | Identifier | Call | Index | Prop;

// @public (undocumented)
const FALSE: {
Expand Down Expand Up @@ -502,6 +504,12 @@ type Meta = NodeBase & {
value: Expression;
};

// @public (undocumented)
type Minus = NodeBase & {
type: 'minus';
expr: Expression;
};

// @public (undocumented)
type Mul = NodeBase & {
type: 'mul';
Expand Down Expand Up @@ -598,6 +606,12 @@ export type ParserPlugin = (nodes: Ast.Node[]) => Ast.Node[];
// @public (undocumented)
export type PluginType = 'validate' | 'transform';

// @public (undocumented)
type Plus = NodeBase & {
type: 'plus';
expr: Expression;
};

// @public
type Pos = {
line: number;
Expand Down
25 changes: 25 additions & 0 deletions src/interpreter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,24 @@ export class Interpreter {
}
}

case 'plus': {
const v = await this._eval(node.expr, scope, callStack);
if (isControl(v)) {
return v;
}
assertNumber(v);
return v;
}

case 'minus': {
const v = await this._eval(node.expr, scope, callStack);
if (isControl(v)) {
return v;
}
assertNumber(v);
return NUM(-v.value);
}

case 'not': {
const v = await this._eval(node.expr, scope, callStack);
if (isControl(v)) {
Expand Down Expand Up @@ -813,7 +831,14 @@ export class Interpreter {
}
}

case 'namedTypeSource':
case 'fnTypeSource':
case 'attr': {
throw new Error('invalid node type');
}

default: {
node satisfies never;
throw new Error('invalid node type');
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ export type Expression =
Null |
Obj |
Arr |
Plus |
Minus |
Not |
Pow |
Mul |
Expand Down Expand Up @@ -162,6 +164,16 @@ export function isExpression(x: Node): x is Expression {
return expressionTypes.includes(x.type);
}

export type Plus = NodeBase & {
type: 'plus'; // 正号
expr: Expression; // 式
};

export type Minus = NodeBase & {
type: 'minus'; // 負号
expr: Expression; // 式
};

export type Not = NodeBase & {
type: 'not'; // 否定
expr: Expression; // 式
Expand Down
12 changes: 2 additions & 10 deletions src/parser/syntaxes/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,16 @@ function parsePrefix(s: ITokenStream, minBp: number): Ast.Expression {

switch (op) {
case TokenKind.Plus: {
// 数値リテラル以外は非サポート
if (expr.type === 'num') {
return NODE('num', { value: expr.value }, startPos, endPos);
} else {
throw new AiScriptSyntaxError('currently, sign is only supported for number literal.', startPos);
}
// TODO: 将来的にサポートされる式を拡張
// return NODE('plus', { expr }, startPos, endPos);
return NODE('plus', { expr }, startPos, endPos);
}
case TokenKind.Minus: {
// 数値リテラル以外は非サポート
if (expr.type === 'num') {
return NODE('num', { value: -1 * expr.value }, startPos, endPos);
} else {
throw new AiScriptSyntaxError('currently, sign is only supported for number literal.', startPos);
}
// TODO: 将来的にサポートされる式を拡張
// return NODE('minus', { expr }, startPos, endPos);
return NODE('minus', { expr }, startPos, endPos);
}
case TokenKind.Not: {
return NODE('not', { expr }, startPos, endPos);
Expand Down
10 changes: 9 additions & 1 deletion src/parser/visit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,16 @@ function visitNodeInner(node: Ast.Node, fn: (node: Ast.Node, ancestors: Ast.Node
result.dest = visitNodeInner(result.dest, fn, ancestors) as Ast.Assign['dest'];
break;
}
case 'plus': {
result.expr = visitNodeInner(result.expr, fn, ancestors) as Ast.Plus['expr'];
break;
}
case 'minus': {
result.expr = visitNodeInner(result.expr, fn, ancestors) as Ast.Minus['expr'];
break;
}
case 'not': {
result.expr = visitNodeInner(result.expr, fn, ancestors) as Ast.Return['expr'];
result.expr = visitNodeInner(result.expr, fn, ancestors) as Ast.Not['expr'];
break;
}
case 'if': {
Expand Down
20 changes: 20 additions & 0 deletions test/syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,26 @@ describe('operators', () => {

});

describe('plus', () => {
test.concurrent('Basic', async () => {
const res = await exe(`
let a = 1
<: +a
`);
eq(res, NUM(1));
})
})

describe('minus', () => {
test.concurrent('Basic', async () => {
const res = await exe(`
let a = 1
<: -a
`);
eq(res, NUM(-1));
})
})

describe('not', () => {
test.concurrent('Basic', async () => {
const res = await exe(`
Expand Down
1 change: 1 addition & 0 deletions unreleased/unary-sign-operators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- 単項演算子の正号 `+`・負号 `-`が数値リテラル以外の式にも使用できるようになりました。

0 comments on commit 6118f9e

Please sign in to comment.