diff --git a/bootstrap/parser.nim b/bootstrap/parser.nim index 3e9fe1c..25d9567 100644 --- a/bootstrap/parser.nim +++ b/bootstrap/parser.nim @@ -601,12 +601,10 @@ proc parseUnary(p: var Parser): Expr = case p.peek() of tkBorrow: discard p.advance() # borrow - let isMut = p.check(tkMut) + discard p.expect(tkAmp, "expected '&' after 'borrow'") + var isMut = p.check(tkMut) if isMut: discard p.advance() # mut - discard p.expect(tkAmp, "expected '&' after 'borrow'") - if isMut and p.check(tkMut): - discard p.advance() # redundant mut after & let operand = p.parseUnary() # parse the moved value return Expr(kind: ekBorrow, loc: loc, exprBorrowOperand: operand, exprBorrowMutable: isMut) of tkBang, tkMinus, tkTilde, tkStar, tkAmp: diff --git a/examples/borrow.bux b/examples/borrow.bux new file mode 100644 index 0000000..2b66204 --- /dev/null +++ b/examples/borrow.bux @@ -0,0 +1,33 @@ +// borrow.bux — Test explicit borrow expressions + +struct Point { + x: int; + y: int; +} + +// NOT @[Checked] — borrow keyword available everywhere +func MovePoint(p: *Point) { + let ref: &Point = borrow &p; + let x: int = (*ref).x; +} + +// @[Checked] enables borrow protection +@[Checked] +func SwapPoints(a: *Point, b: *Point) { + let ra: &mut Point = borrow &mut a; + let rb: &mut Point = borrow &mut b; + let tmp: int = (*ra).x; + (*ra).x = (*rb).x; + (*rb).x = tmp; +} + +func Main() -> int { + var p1: Point; + p1.x = 10; + p1.y = 20; + var p2: Point; + p2.x = 30; + p2.y = 40; + SwapPoints(&p1, &p2); + return 0; +} diff --git a/tests/borrow_test b/tests/borrow_test index f4fb714..f71af4e 100755 Binary files a/tests/borrow_test and b/tests/borrow_test differ diff --git a/tests/borrow_test.nim b/tests/borrow_test.nim index 4bc4b80..80b294c 100644 --- a/tests/borrow_test.nim +++ b/tests/borrow_test.nim @@ -26,7 +26,6 @@ func Main() -> int { } """) check(not res.hasErrors) - test "@[Checked] function rejects write through &T": let res = checkSource(""" @[Checked] @@ -54,7 +53,6 @@ func Main() -> int { } """) check(not res.hasErrors) - test "&T allows reading": let res = checkSource(""" @[Checked] @@ -68,7 +66,6 @@ func Main() -> int { } """) check(not res.hasErrors) - test "own T type parses and resolves": let res = checkSource(""" struct Box { @@ -83,7 +80,6 @@ func Main() -> int { } """) check(not res.hasErrors) - test "@[Checked] rejects double mutable borrow in call": let res = checkSource(""" @[Checked] @@ -139,7 +135,6 @@ func Main() -> int { } """) check(not res.hasErrors) - test "@[Checked] move in assignment": let res = checkSource(""" struct Box { @@ -172,3 +167,46 @@ func Main() -> int { } """) check(not res.hasErrors) + + test "borrow &mut expr parses and type-checks": + let res = checkSource(""" +struct Point { + x: int; + y: int; +} +func Main() -> int { + var p: Point; + p.x = 10; + let r: &mut Point = borrow &mut p; + return 0; +} +""") + check(not res.hasErrors) + + test "@[Shared] attribute parses without errors": + let res = checkSource(""" +@[Shared] +func SharedFunc() -> int { + return 42; +} +func Main() -> int { + return SharedFunc(); +} +""") + check(not res.hasErrors) + + test "borrow & expr with shared ref": + let res = checkSource(""" +struct Point { + x: int; + y: int; +} +func Main() -> int { + var p: Point; + p.x = 10; + let r: &Point = borrow &p; + let val: int = (*r).x; + return val; +} +""") + check(not res.hasErrors) \ No newline at end of file