basic for loop + examples -> era3

This commit is contained in:
Neemek 2026-07-13 10:01:13 +02:00
parent dd7af341a3
commit 0bc8b2ef55
Signed by: neemek
GPG key ID: 84FFE4D7D40AB25E
24 changed files with 222 additions and 201 deletions

40
bad.ang
View file

@ -1,40 +0,0 @@
import "lib/math.ang"
primes := [2]
func is_prime(x: number) boolean {
i := 0
while i < primes.length() && primes.at(i)*primes.at(i) < x {
if mod(x, primes.at(i)) == 0 {
return false
}
i = i + 1
}
return true
}
n := 1
max := 100000
while n < max {
n = n + 2
if is_prime(n) {
primes.append(n)
# Update counter
print(char(0x0D))
print(str(n))
print("/")
print(str(max))
print(char(0x09))
print(str(roundd(n/max*100, 2)))
print("%")
print(char(0x09))
print(str(primes.length()))
print(" primes")
}
}
write(str(primes))

View file

@ -1,15 +0,0 @@
MAX_WIDTH := 16
print(" ")
w := 1
n := 0x21
while n < 0xA0 {
print(char(n))
n = n + 1
w = w + 1
if w >= MAX_WIDTH {
write("")
w = 0
}
}

View file

@ -1,24 +0,0 @@
passphrase := "Hello world!".split("")
start := [0, 0, 0]
modulus := 10
base := byte("!")
i := 0
n := 0
while n < passphrase.length() {
b := byte(passphrase.at(n))
v = start.at(i) + b - base
while v >= modulus {
v = v - modulus
}
start.put(i, v)
if i >= 3 {
i = 0
}
n = n + 1
}

View file

@ -153,6 +153,7 @@ func (c *Compiler) add(instruction Bytecode) {
c.advance(1) c.advance(1)
} }
// addConstant add both a constant (if it is not already defined), and add the index of it to the bytecode
func (c *Compiler) addConstant(value Value) { func (c *Compiler) addConstant(value Value) {
chunk := c.Chunk chunk := c.Chunk
for i := 0; i < len(chunk.Constants); i++ { for i := 0; i < len(chunk.Constants); i++ {
@ -165,6 +166,10 @@ func (c *Compiler) addConstant(value Value) {
chunk.Constants = append(chunk.Constants, value) chunk.Constants = append(chunk.Constants, value)
if len(chunk.Constants) > 256 {
panic("too many constants (>256)")
}
c.add(Bytecode(len(chunk.Constants) - 1)) c.add(Bytecode(len(chunk.Constants) - 1))
} }
@ -472,7 +477,6 @@ func (c *Compiler) compile(tree Node) (TypeSignature, error) {
c.add(InstructionJumpFalse) c.add(InstructionJumpFalse)
jumpValuePos = c.ip jumpValuePos = c.ip
c.advance(2) c.advance(2)
} }
c.add(InstructionPop) c.add(InstructionPop)
@ -492,6 +496,74 @@ func (c *Compiler) compile(tree Node) (TypeSignature, error) {
return &CompositeSignature{dt, &NilSignature{}}, nil return &CompositeSignature{dt, &NilSignature{}}, nil
case ForNodeType:
n := tree.(*ForNode)
is, err := c.compile(n.iterator)
if err != nil {
return nil, err
}
iteratorSignature := &FunctionSignature{
[]TypeSignature{},
&TupleSignature{
[]TypeSignature{
&AnySignature{},
&BooleanSignature{},
},
},
}
if !iteratorSignature.Contains(is) {
return nil, c.error(fmt.Sprintf("cannot iterate with non-iterator %s (must be %s)", is, iteratorSignature), n.iterator)
}
outputSig := is.(*FunctionSignature).Out.(*TupleSignature).Contents[0]
ipos := c.ip
c.addDescend()
c.add(InstructionDuplicate)
c.add(InstructionCall)
c.add(InstructionDestructureTuple)
// if no more items; jump to end
c.add(InstructionJumpFalse)
jmpValuePos := c.ip
c.advance(2)
if n.counter.Type() != ReferenceNodeType {
return nil, c.error("cannot use non-variable as a counter", n.counter)
}
name := n.counter.(*ReferenceNode).name
c.add(InstructionDeclareLocal)
c.addConstant(&StringValue{
name,
})
c.add(InstructionPop)
c.registerVar(name, outputSig)
_, err = c.compile(n.logic)
if err != nil {
return nil, err
}
c.add(InstructionPop)
c.addAscend()
c.add(InstructionLoop)
c.addU16(uint16(c.ip - ipos + 2))
// end of loop
c.putU16(jmpValuePos, uint16(c.ip-jmpValuePos-2))
c.add(InstructionPop)
c.add(InstructionPop)
c.add(InstructionNil)
return &NilSignature{}, nil
case AssignNodeType: case AssignNodeType:
n := tree.(*AssignNode) n := tree.(*AssignNode)

View file

@ -57,6 +57,8 @@ const (
TokenElse TokenElse
TokenImport TokenImport
TokenType TokenType
TokenFor
TokenIn
TokenComma TokenComma
TokenDot TokenDot
@ -178,6 +180,10 @@ func (t TokenKind) String() string {
return "newline" return "newline"
case TokenType: case TokenType:
return "type" return "type"
case TokenFor:
return "for"
case TokenIn:
return "in"
} }
panic("UNDEFINED TOKENTYPE STRING CONVERSION") panic("UNDEFINED TOKENTYPE STRING CONVERSION")
@ -196,6 +202,8 @@ var Keywords = map[string]TokenKind{
"while": TokenWhile, "while": TokenWhile,
"breakpoint": TokenBreakpoint, "breakpoint": TokenBreakpoint,
"type": TokenType, "type": TokenType,
"for": TokenFor,
"in": TokenIn,
} }
type Lexer struct { type Lexer struct {

View file

@ -34,6 +34,7 @@ const (
BlockNodeType BlockNodeType
ConditionalNodeType ConditionalNodeType
LoopNodeType LoopNodeType
ForNodeType
AssignNodeType AssignNodeType
InvokeNodeType InvokeNodeType
CallNodeType CallNodeType
@ -501,7 +502,7 @@ func (n ConditionalNode) Bounds() (Pos, Pos) {
return n.start, n.end return n.start, n.end
} }
// LoopNode Loops (for/while) // LoopNode While loops
type LoopNode struct { type LoopNode struct {
condition Node condition Node
do Node do Node
@ -522,6 +523,28 @@ func (n LoopNode) Bounds() (Pos, Pos) {
return n.start, n.end return n.start, n.end
} }
// ForNode For loops
type ForNode struct {
counter Node
iterator Node
logic Node
start Pos
end Pos
}
func (n ForNode) Type() NodeType {
return ForNodeType
}
func (n ForNode) String() string {
return fmt.Sprintf("for %s in %s; %s", n.counter, n.iterator, n.logic)
}
func (n ForNode) Bounds() (Pos, Pos) {
return n.start, n.end
}
// AssignNode assignment // AssignNode assignment
type AssignNode struct { type AssignNode struct {
dest Node dest Node

View file

@ -383,6 +383,38 @@ func (p *Parser) expression(mustBeBlock bool) (Node, error) {
p.prev.End, p.prev.End,
}, nil }, nil
case TokenFor:
p.advance()
start := p.prev.Start
counter, err := p.expression(false)
if err != nil {
return nil, err
}
if err := p.expect(TokenIn, "for-loops must be for each item in an iterator"); err != nil {
return nil, err
}
iterator, err := p.expression(false)
if err != nil {
return nil, err
}
logic, err := p.expression(true)
if err != nil {
return nil, err
}
return &ForNode{
counter,
iterator,
logic,
start,
p.prev.End,
}, nil
default: default:
s, err := p.binary() s, err := p.binary()
if err != nil { if err != nil {

View file

@ -742,7 +742,7 @@ func (v *BuiltinFunctionValue) Type() ValueType {
} }
func (v *BuiltinFunctionValue) String() string { func (v *BuiltinFunctionValue) String() string {
return fmt.Sprintf("<function name=%s builtin>", v.Name) return fmt.Sprintf("<function builtin name=%s>", v.Name)
} }
func (v *BuiltinFunctionValue) DebugString() string { func (v *BuiltinFunctionValue) DebugString() string {

View file

@ -133,6 +133,9 @@ const (
// InstructionFormTuple pop n+1 (u16) items from the stack, and create a new tuple with the items. The top value // InstructionFormTuple pop n+1 (u16) items from the stack, and create a new tuple with the items. The top value
// on the stack is the last value in the tuple. // on the stack is the last value in the tuple.
InstructionFormTuple InstructionFormTuple
// InstructionDestructureTuple pop a tuple, and push all its items to the stack, with the top item on the stack
// being the last item in the tuple.
InstructionDestructureTuple
// InstructionIndexList index into a list. The lower item is the container, and the top item // InstructionIndexList index into a list. The lower item is the container, and the top item
// is the index. [..., container, index] -> [..., item] // is the index. [..., container, index] -> [..., item]
@ -251,6 +254,8 @@ func (b Bytecode) String() string {
return "INDEX_LIST" return "INDEX_LIST"
case InstructionIndexTuple: case InstructionIndexTuple:
return "INDEX_TUPLE" return "INDEX_TUPLE"
case InstructionDestructureTuple:
return "DESTRUCTURE_TUPLE"
} }
return "UNDEFINED" return "UNDEFINED"
} }
@ -605,10 +610,7 @@ var DefaultGlobals = map[string]Value{
&StringSignature{}, &StringSignature{},
), ),
}, },
quickComposite( &FloatSignature{},
&FloatSignature{},
&NilSignature{},
),
}, },
func(vm *VM, _ Value, args []Value) (Value, error) { func(vm *VM, _ Value, args []Value) (Value, error) {
switch v := args[0].(type) { switch v := args[0].(type) {
@ -620,7 +622,7 @@ var DefaultGlobals = map[string]Value{
case *StringValue: case *StringValue:
num, err := strconv.ParseFloat(v.Text, FloatSize) num, err := strconv.ParseFloat(v.Text, FloatSize)
if err != nil { if err != nil {
return &NilValue{}, nil return &FloatValue{}, nil
} }
return &FloatValue{num}, nil return &FloatValue{num}, nil
@ -1014,6 +1016,11 @@ func (vm *VM) Next() bool {
items, items,
}) })
case InstructionDestructureTuple:
t := vm.Stack.Pop().(*TupleValue)
vm.Stack.Push(t.Items...)
case InstructionDescend: case InstructionDescend:
vm.descend() vm.descend()

View file

@ -1,2 +0,0 @@
write(char(0x12) + char(0x85) + char(0x07))

View file

@ -1,11 +0,0 @@
fn counter() -> (fn() -> int) {
i := 0
fn() -> int { i = i + 1 }
}
next := counter()
println(next())
println(next())
println(next())

View file

@ -1,19 +1,20 @@
write("Bonjour à tout!"); println("Bonjour à tout!")
if 1 == 2 { if 1 == 2 {
# unreachable # unreachable
println("Wooot?? One does equal 2????")
} else { } else {
write("Hooray! One does not equal 2!"); println("Hooray! One does not equal 2!")
} }
for (var n = 1; n < 10; n = n + 1) { for n in 0..10 {
write("Run number " + str(n)); println("Run number " + str(n))
} }
var a = 2; a := 2
write(3 * a*a + 10 / 3); println(3 * a*a + 10 / 3)

View file

@ -1,17 +1,8 @@
# calculate fibonacci numbers with a loop # calculate fibonacci numbers with a loop
x := 0 (a, b) := (1, 0)
for _ in 0..100 {
n := 1 (a, b) = (a + b, b)
p := 1 println(a)
while x < 100 {
f := n + p
p = n
n = f
write(f)
x = x + 1
} }

View file

@ -1,6 +1,6 @@
func sum(a, b) { fn sum(a: int, b: int) -> int {
return a + b a + b
} }
write(sum(1, 2)) println(sum(1, 2))

View file

@ -1,4 +1,4 @@
func f(x) { fn f(x) {
return x*x - 4 return x*x - 4
} }

View file

@ -1,13 +1,11 @@
write("Hello world!") println("Hello world!")
a := 1 + 2 a := 1 + 2
println(a)
write(a)
if a > 2 { if a > 2 {
write("Hooray!! a is greater than 2!!!!") println("Hooray!! a is greater than 2!!!!")
} else { } else {
write("oh nooo!!! a is less than or equal to 2!!!!!!!!!!") println("oh nooo!!! a is less than or equal to 2!!!!!!!!!!")
} }

View file

@ -1,3 +1,3 @@
import "math.ang" import "math.ang"
write(sqrt(2)) println(sqrt(2.0))

View file

@ -1,51 +1,47 @@
# Empty list # Empty list
write([]) println([])
# List with items # List with items
write([3, 1, 4, 1, 5, 9, 2, 6, 5]) println([3, 1, 4, 1, 5, 9, 2, 6, 5])
# List with items of different types # List with items of different types
write(["", "私はかっこいいです。", true, nil, nil, 1, 2]) println(["", "私はかっこいいです。", true, nil, nil, 1, 2])
a := [] a := []
a = a.append(1) a = a + [1]
a = a.append(2) a = a + [2]
write(a) println(a)
list := [] list := []
n := 0
x := 0 x := 0
while n < 100 { for n in 0..100 {
x = x + 2*n + 1 x = x + 2*n + 1
list = list.append(x) list = list + [x]
n = n + 1
} }
write(list) println(list)
write(list.map(func(a) { println(list.map(func(a) {
return a - 1 return a - 1
})) }))
write(list.length()) println(list.length())
write(list.at(69)) println(list.at(69))
other := [] other := []
a := 1 for a in 0..=10 {
while a <= 10 {
other = other.append(a) other = other.append(a)
a = a + 1
} }
sum := other.reduce(func(tot, x) { sum := other.reduce(func(tot, x) {
return tot + x return tot + x
}, 0) }, 0)
write(sum) println(sum)
assert(sum == a*(a-1)/2) assert(sum == a*(a-1)/2)

View file

@ -20,9 +20,10 @@ tot = tot * 6.0
# get the absolute value of a number # get the absolute value of a number
fn abs(x: float) -> float { fn abs(x: float) -> float {
if x < 0.0 { if x < 0.0 {
return -x -x
} else {
x
} }
return x
} }
# calculate an approximation of the square root of tot using # calculate an approximation of the square root of tot using

View file

@ -1,16 +1,15 @@
import "math.ang" import "math.ang"
func r_x(t) { fn r_x(t: float) -> float {
return 8*(exp(-t) - t) return 8.0*(exp(-t) - t)
} }
func r_y(t) { fn r_y(t: float) -> float {
return 5*(exp(-t) - t) return 5.0*(exp(-t) - t)
} }
func r(t) { fn r(t: float) -> (float, float) {
return format("(%s, %s)", [r_x(t), r_y(t)]) return (r_x(t), r_y(t))
} }
write(r(1)) println(r(1.0))
write()

View file

@ -1,4 +0,0 @@
import "lib/honning.ang"
write(_bell+_italic+"Hello "+_underline+"world "+_strike+"micheal"+_reset)

15
imp.ang
View file

@ -1,15 +0,0 @@
func is_cool(x: number|string) boolean {
if x == "cool" {
return true
} else if x == 69 {
return true
}
return nil
}
write(str(is_cool("not cool")))
write(str(is_cool("cool")))
write(str(is_cool(0)))
write(str(is_cool(69)))

View file

@ -1,5 +1,5 @@
fn map(list: [any], f: fn(any) -> any) -> [any] { fn (l: list) map(list: [any], f: fn(any) -> any) -> [any] {
out := [] out := []
i := 0 i := 0

View file

@ -9,7 +9,7 @@ E := 2.718281828459045235360287471352
# returned value is x. # returned value is x.
fn absf(x: float) -> float { fn absf(x: float) -> float {
# if the number is negative # if the number is negative
if x < 0 { if x < 0.0 {
# negate it so it's positive # negate it so it's positive
return -x return -x
} }
@ -26,7 +26,7 @@ fn absi(n: int) -> int {
} }
DERIVE_DX := 0.00000001 DERIVE_DX := 0.00000001
fn derive(f: fn(float) -> float, x: float) float { fn derive(f: fn(float) -> float, x: float) -> float {
return (f(x + DERIVE_DX) - f(x))/DERIVE_DX return (f(x + DERIVE_DX) - f(x))/DERIVE_DX
} }
@ -35,7 +35,7 @@ fn newtons(f: fn(float) -> float) -> float {
pg := 0.0 pg := 0.0
g := 1.0 g := 1.0
while abs(g - pg) > NEWTONS_ACC { while absf(g - pg) > NEWTONS_ACC {
pg = g pg = g
g = pg - f(pg) / derive(f, pg) g = pg - f(pg) / derive(f, pg)
} }
@ -53,12 +53,14 @@ fn sqrt(x: float) -> float {
ng := x ng := x
g := 1.0 g := 1.0
while abs(g - ng) > MAX_SQRT_DX { while absf(g - ng) > MAX_SQRT_DX {
g = ng g = ng
# create new guess # create new guess
ng = (g + x / g) / 2 ng = (g + x / g) / 2.0
} }
g
} }
# floor(x) # floor(x)
@ -82,7 +84,7 @@ fn round(x: float) -> float {
f := floor(x) f := floor(x)
if x - f > 0.5 { if x - f > 0.5 {
return f + 1 return f + 1.0
} }
return f return f
@ -93,16 +95,16 @@ fn round(x: float) -> float {
# n: number; the number to divide by # n: number; the number to divide by
# Return the rest from a division of x by n. # Return the rest from a division of x by n.
fn mod(x: float, n: float) -> float { fn mod(x: float, n: float) -> float {
if x == 0 { if x == 0.0 {
return 0 return 0.0
} }
if x < 0 { if x < 0.0 {
while x + n <= 0 { while x + n <= 0.0 {
x = x + n x = x + n
} }
} else { } else {
while x - n >= 0 { while x - n >= 0.0 {
x = x - n x = x - n
} }
} }
@ -123,7 +125,7 @@ fn sm_exp(x: float) -> float {
x_pow := x x_pow := x
f := 1.0 f := 1.0
while abs(tot - p_tot) > SM_EXP_ACC { while absf(tot - p_tot) > SM_EXP_ACC {
p_tot = tot p_tot = tot
t := x_pow / f t := x_pow / f
tot = tot + t tot = tot + t
@ -139,18 +141,18 @@ fn sm_exp(x: float) -> float {
# x: number; any number # x: number; any number
# Get an approximate value of e raised to the power of x. # Get an approximate value of e raised to the power of x.
fn exp(x: float) -> float { fn exp(x: float) -> float {
n := abs(x) n := absf(x)
tot := 1.0 tot := 1.0
while n >= 1 { while n >= 1.0 {
tot = tot * E tot = tot * E
n = n - 1 n = n - 1.0
} }
if n > 0.0 { if n > 0.0 {
tot = tot * sm_exp(n) tot = tot * sm_exp(n)
} }
if x < 0 { if x < 0.0 {
1.0/tot 1.0/tot
} else { } else {
tot tot
@ -166,9 +168,9 @@ fn ln(x: float) -> float {
pg := 0.0 pg := 0.0
g := 1.0 g := 1.0
while abs(pg - g) > LN_ACC { while absf(pg - g) > LN_ACC {
pg = g pg = g
g = pg + x / exp(pg) - 1 g = pg + x / exp(pg) - 1.0
} }
return g return g
@ -194,7 +196,7 @@ fn log(a: float, b: float) -> float {
pg := 0.0 pg := 0.0
g := 1.0 g := 1.0
while abs(g - pg) > LOG_ACC { while absf(g - pg) > LOG_ACC {
pg = g pg = g
g = pg - 1.0/ln_b - a/(ln_b*pow(b, pg)) g = pg - 1.0/ln_b - a/(ln_b*pow(b, pg))
} }
@ -211,7 +213,7 @@ fn sin(x: float) -> float {
x = mod(x, 2.0*PI) x = mod(x, 2.0*PI)
if x > PI { if x > PI {
x = PI - x x = PI - x
f = -1 f = -1.0
} }
# compute sine with a taylor series mock function of sine (valid between -pi and +pi) # compute sine with a taylor series mock function of sine (valid between -pi and +pi)
@ -220,7 +222,7 @@ fn sin(x: float) -> float {
i := 1.0 i := 1.0
s := -1.0 s := -1.0
while i <= 19 { while i <= 19.0 {
i = i + 2.0 i = i + 2.0
l = s * l * x / i / (i-1.0) l = s * l * x / i / (i-1.0)
@ -235,13 +237,15 @@ fn sin(x: float) -> float {
# cos(x) # cos(x)
# x: number; an angle in radians # x: number; an angle in radians
# Get the cosine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine # Get the cosine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine
func cos(x: number) number { fn cos(x: float) -> float {
# todo # todo
0.0
} }
# tan(x) # tan(x)
# x: number; an angle in radians # x: number; an angle in radians
# Get the tangent of an angle. https://en.wikipedia.org/wiki/Tangent # Get the tangent of an angle. https://en.wikipedia.org/wiki/Tangent
func tan(x: number) number { fn tan(x: float) -> float {
# todo # todo
0.0
} }