# 運算子與運算式

``````println('Just' + 'in') # 顯示 Justin
``````

• 算術運算：`+``-``*``/``%`
• 邏輯運算：`and``or``not`
• 關係運算：`==``!=``>=``>``<=`
• 位元運算：`&``|``^``>>``<<`
• 實例運算：`new`
• 物件操作：`.`

`and``or` 有捷徑運算的效果，運算元不用是 `true``false` 的結果，`0``''``false` 都會被當成不成立，其他都是成立，`and``or` 在可以判定結果成立與否時，當時的運算元會被傳回。例如：

``````println(0 or 'Justin')          # 顯示 Justin
println('Justin' and 'Monica')  # 顯示 Monica
``````

``````x = (1 + 2) * (3 + 4)
println(x)  # 顯示 21
``````

`=` 是個指定，除了它之外，還有 `+=``-=``*=``/=``%=``&=``|=``^=``<<=``>>=`，這之後的文件再來談。

``````class Context {
}

class Num {
constructor(value) {
this.value = value;
}

evaluate(context) {
return this;
}
}

constructor(left, right) {
this.left = left;
this.right = right;
}

evaluate(context) {
return new Num(
this.left.evaluate(context).value + this.right.evaluate(context).value
);
}
}

const r = new Add(new Num(1), new Num(2)).evaluate(new Context());
``````

``````class Multiply {
constructor(left, right) {
this.left = left;
this.right = right;
}

evaluate(context) {
return new Num(
this.left.evaluate(context).value * this.right.evaluate(context).value
);
}
}

const node = new Multiply(
new Add(new Num(1), new Num(2)),
new Add(new Num(3), new Num(4))
);

const r = node.evaluate(new Context());
``````

``````// expression

function exprAst(tokenables) {
if(isBinaryOperator(tokenable.value)) {
return reduceBinary(stack, tokenable);
}

if(isUnaryOperator(tokenable.value)) {
return reduceUnary(stack, tokenable);
}

return stack.push(
OPERAND_PARSER.parse(tokenable)
);
}, new Stack()).top;
}

function precedence(operator) {
switch(operator) {
case '.':    return 14;
case 'new':  return 13;
case '\$neg': return 12;
case 'not':  return 11;
case '*': case '/': case '%':
return 10;
case '+': case '-':
return 9;
case '<<': case '>>':
return 8;
case '>=': case '>': case '<=': case '<':
return 7;
case '==': case '!=':
return 6;
case '&':    return 5;
case '^':    return 4;
case '|':    return 3;
case 'and':  return 2;
case 'or':   return 1;
default:     return 0;
}
}

``````

``````class AndOperator {
constructor(left, right) {
this.left = left;
this.right = right;
}

evaluate(context) {
const maybeCtxLeft = this.left.evaluate(context); // 先估值左運算元
return maybeCtxLeft.notThrown(
left => {
if(left.value === undefined ? left.toString(context) : left.value) {
// 左運算元成立才會執行右運算元估值
return this.right.evaluate(context).notThrown(right => right);
}
return left;
}
);
}
}
``````