postfix/prefix operators handled correctly

This commit is contained in:
2026-02-10 08:12:27 -06:00
parent 96f8157039
commit ad863fb89b
4 changed files with 238 additions and 17 deletions

Binary file not shown.

View File

@@ -499,6 +499,9 @@ var parse = function(tokens, src, filename, tokenizer) {
var index = null
var arg = null
var args_list = null
var one_node = null
var binop_node = null
var op = null
if (node == null) return null
while (true) {
start = tok
@@ -574,6 +577,10 @@ var parse = function(tokens, src, filename, tokenizer) {
var node = null
var expr = null
var k = tok.kind
var operand = null
var one_node = null
var binop_node = null
var op = null
if (k == "!") {
advance()
node = ast_node("!", start)
@@ -602,19 +609,22 @@ var parse = function(tokens, src, filename, tokenizer) {
ast_node_end(node)
return node
}
if (k == "++") {
if (k == "++" || k == "--") {
advance()
node = ast_node("++", start)
node.expression = parse_unary()
node.postfix = false
ast_node_end(node)
return node
}
if (k == "--") {
advance()
node = ast_node("--", start)
node.expression = parse_unary()
node.postfix = false
operand = parse_unary()
one_node = ast_node("number", start)
one_node.number = 1
one_node.value = "1"
ast_node_end(one_node)
op = "+"
if (k == "--") op = "-"
binop_node = ast_node(op, start)
binop_node.left = operand
binop_node.right = one_node
ast_node_end(binop_node)
node = ast_node("assign", start)
node.left = operand
node.right = binop_node
ast_node_end(node)
return node
}
@@ -699,6 +709,13 @@ var parse = function(tokens, src, filename, tokenizer) {
"&&=": "&&=", "||=": "||="
}
var compound_binop = {
"+=": "+", "-=": "-", "*=": "*", "/=": "/", "%=": "%",
"<<=": "<<", ">>=": ">>", ">>>=": ">>>",
"&=": "&", "^=": "^", "|=": "|", "**=": "**",
"&&=": "&&", "||=": "||"
}
parse_assign = function(unused) {
var left_node = parse_ternary()
var start = null
@@ -707,6 +724,8 @@ var parse = function(tokens, src, filename, tokenizer) {
var node = null
var left_kind = null
var right_kind = null
var binop = null
var binop_node = null
if (left_node == null) return null
start = tok
kind = assign_ops[tok.kind]
@@ -719,12 +738,23 @@ var parse = function(tokens, src, filename, tokenizer) {
advance()
right_node = parse_assign()
node = ast_node(kind, start)
node.left = left_node
node.right = right_node
if (left_node.kind == "[" && left_node.right == null) node.push = true
if (right_node != null && right_node.kind == "[" && right_node.right == null) node.pop = true
binop = compound_binop[kind]
if (binop != null) {
binop_node = ast_node(binop, start)
binop_node.left = left_node
binop_node.right = right_node
ast_node_end(binop_node)
node = ast_node("assign", start)
node.left = left_node
node.right = binop_node
} else {
node = ast_node(kind, start)
node.left = left_node
node.right = right_node
if (left_node.kind == "[" && left_node.right == null) node.push = true
if (right_node != null && right_node.kind == "[" && right_node.right == null) node.pop = true
}
ast_node_end(node)
return node

Binary file not shown.

View File

@@ -1058,6 +1058,197 @@ run("modulo equals", function() {
if (x != 1) fail("modulo equals failed")
})
// ============================================================================
// COMPOUND ASSIGNMENT ON PROPERTIES
// ============================================================================
run("plus equals on property", function() {
var obj = {x: 10}
obj.x += 5
if (obj.x != 15) fail("obj.x += 5")
})
run("minus equals on property", function() {
var obj = {x: 10}
obj.x -= 3
if (obj.x != 7) fail("obj.x -= 3")
})
run("times equals on property", function() {
var obj = {x: 4}
obj.x *= 3
if (obj.x != 12) fail("obj.x *= 3")
})
run("divide equals on property", function() {
var obj = {x: 12}
obj.x /= 3
if (obj.x != 4) fail("obj.x /= 3")
})
run("modulo equals on property", function() {
var obj = {x: 10}
obj.x %= 3
if (obj.x != 1) fail("obj.x %= 3")
})
run("compound assign preserves other properties", function() {
var obj = {x: 10, y: 20}
obj.x += 5
if (obj.x != 15) fail("x wrong")
if (obj.y != 20) fail("y changed")
})
run("compound assign nested property", function() {
var obj = {inner: {val: 10}}
obj.inner.val += 5
if (obj.inner.val != 15) fail("nested += failed")
})
run("compound assign chained", function() {
var obj = {x: 1}
obj.x += 2
obj.x += 3
obj.x += 4
if (obj.x != 10) fail("chained += failed")
})
// ============================================================================
// COMPOUND ASSIGNMENT ON ARRAY ELEMENTS
// ============================================================================
run("plus equals on array element", function() {
var arr = [100, 200, 300]
arr[0] += 50
if (arr[0] != 150) fail("arr[0] += 50")
})
run("minus equals on array element", function() {
var arr = [100, 200, 300]
arr[1] -= 50
if (arr[1] != 150) fail("arr[1] -= 50")
})
run("times equals on array element", function() {
var arr = [5]
arr[0] *= 6
if (arr[0] != 30) fail("arr[0] *= 6")
})
run("compound assign computed property", function() {
var obj = {a: 10, b: 20}
var key = "a"
obj[key] += 5
if (obj.a != 15) fail("obj[key] += 5")
})
run("compound assign array element preserves others", function() {
var arr = [10, 20, 30]
arr[1] += 5
if (arr[0] != 10) fail("arr[0] changed")
if (arr[1] != 25) fail("arr[1] wrong")
if (arr[2] != 30) fail("arr[2] changed")
})
// ============================================================================
// PREFIX INCREMENT/DECREMENT ON PROPERTIES
// ============================================================================
run("prefix increment on property", function() {
var obj = {x: 5}
var y = ++obj.x
if (y != 6) fail("return value")
if (obj.x != 6) fail("side effect")
})
run("prefix decrement on property", function() {
var obj = {x: 5}
var y = --obj.x
if (y != 4) fail("return value")
if (obj.x != 4) fail("side effect")
})
run("prefix increment on array element", function() {
var arr = [10]
var y = ++arr[0]
if (y != 11) fail("return value")
if (arr[0] != 11) fail("side effect")
})
run("prefix decrement on array element", function() {
var arr = [10]
var y = --arr[0]
if (y != 9) fail("return value")
if (arr[0] != 9) fail("side effect")
})
// ============================================================================
// INCREMENT/DECREMENT IN LOOPS AND EXPRESSIONS
// ============================================================================
run("compound assign in for loop", function() {
var sum = 0
var i = 0
for (i = 0; i < 5; i++) {
sum += i
}
if (sum != 10) fail("sum should be 10")
})
run("compound assign property in loop", function() {
var obj = {count: 0}
var i = 0
for (i = 0; i < 5; i++) {
obj.count += 1
}
if (obj.count != 5) fail("count should be 5")
})
run("prefix increment in expression", function() {
var x = 5
var y = 10 + ++x
if (y != 16) fail("10 + ++x should be 16")
if (x != 6) fail("x should be 6")
})
run("compound assign bitwise and-equals", function() {
var x = 15
x &= 6
if (x != 6) fail("15 & 6 should be 6")
})
run("compound assign bitwise or-equals", function() {
var x = 5
x |= 3
if (x != 7) fail("5 | 3 should be 7")
})
run("compound assign bitwise xor-equals", function() {
var x = 5
x ^= 3
if (x != 6) fail("5 ^ 3 should be 6")
})
run("compound assign left shift-equals", function() {
var x = 1
x <<= 3
if (x != 8) fail("1 << 3 should be 8")
})
run("compound assign right shift-equals", function() {
var x = 16
x >>= 2
if (x != 4) fail("16 >> 2 should be 4")
})
run("compound assign bitwise on property", function() {
var obj = {flags: 5}
obj.flags |= 8
if (obj.flags != 13) fail("5 | 8 should be 13")
obj.flags &= 12
if (obj.flags != 12) fail("13 & 12 should be 12")
})
// ============================================================================
// EDGE CASES AND SPECIAL VALUES
// ============================================================================