Skip to content
/ axol Public

Minimalist programming language simple to read, write, extend

License

Notifications You must be signed in to change notification settings

whyolet/axol

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 

Repository files navigation

Axolotl

  • Minimalist programming language simple to read, write, extend.
  • Axol is named after the axolotl animal for its ability to regrow missing body parts and for being cute.
  • Version: 0.4.0
print("hello world")
# hello world

a=1
print(a)
# 1

b="c"
print("{a}d{b}")
# 1dc

print("e\"f\{g\}h\\i\
  j
  k"
)
# e"f{g}h\ij
#   k

print("""
  e"f{g}h\ij
    k
""")
# e"f{g}h\ij
#   k

f={b}

print(f)
# {1234567890}
# (function address is shown
# instead of function code
# to be able to compare functions,
# that may have the same code,
# yet they are still not the same function)

print(f)
# {}
# (to keep docs simple,
# let's skip the address...)

print(f)
# f
# (...or just show the function name)

print(f())
# c
# (because f={b} and b="c")

dup={
  val=$.0
  "{val}{val}"
}

print(dup("he"))
# hehe

g=["he"]

print(g)
# ["he"]

print(g.0)
# he

h=["i" "j" key="val" m="n" o="p"]

print(h.1)
# j

print(h.key)
# val

[
  pos=[q r="s" t="u"]
  kv=[key m="v" w="x"]
  rest=[y]
]=h

print(q r t)
# i j u

print(key m w)
# val n x

print(y)
# [o="p"]

print(["a" y...])
# ["a" o="p"]

print(["a" o="p" o="q"])
# ["a" o="q"]

greet={
  [pos=[name] kv=[how="hello"]]=$
  print("{how}, {name}!")
}

greet("Alice")
# hello, Alice!

greet("Bob" how="hi")
# hi, Bob!

if(eq(sum(2 2) 4)
  then={print("ok")}
  else={print("why?")}
)
# ok

if(2|sum(2)|eq(4)
  then={"ok"}
  else={"why?"}
)|print
# ok

echo={print($)}

"a"|echo("b" c="d")
# ["a" "b" c="d"] 

then={
  [pos=[cond do]]=$
  if(cond then=do)
}

2|sum(2)|eq(4)|then({
  print("ok")
})
# ok

else={
  [pos=[cond do]]=$
  if(cond else=do)
}

2|sum(2)|eq(4)|else({
  print("why?")
})

print({42}|is({}))
# true

print({42}|is(""))
# false

print("42"|is(""))
# true

{
  print($|is([]))
}()
# true

while={
  [pos=[cond] kv=[do={}]]=$
  cond|is({})|else({
    throw("replace while(condition ...) \
      with while({condition} ...) \
      to check it many times")
  })
  loop({
    if(cond() then=do else=break)
  })
}

i=4
while({i} do={
  i|print
  up(i=i|sub(1))
})  # 4 3 2 1

[kv=[foo]]=import("./lib.axol")
foo()

py=import("python")
# Not relative.
# Finds nearest parent dir with
# `axol/python.axol` file,
# which may be a symlink
# (created by a package manager)
# to the specific version file like
# `axol/python/3.14.2.axol`,
# which has auto-generated bindings to CPython 3.14.2
# including its built-in functions
# https://docs.python.org/3/library/functions.html
# like `__import__("package")`
# https://docs.python.org/3/library/functions.html#import__
# giving access to python standard library
# https://docs.python.org/3/library/index.html
# and installed third-party packages.

dt=py.__import__("datetime")

getNow={
  dt.datetime.now(dt.UTC).isoformat()
}

print(getNow())
# 2026-12-31T23:59:59Z

log=[]
log.levelNames="debug info warn error"|split(" ")
log.levelLetters=log.levelNames\
  |map({$.val.0|upper})|join("")
log.levels=[]
log.levelNames|each({
  log.levels[$.val]=$.key
}]
log.level=log.levels.info
log.print=print
log.do={
  [pos=[level] rest=[vals]]=$
  level|lt(log.level)|then(return)
  letter=log.levelLetters[level]
  log.print("{getNow()} {letter} {vals}")
}
log.levels|each({
  level=$.val
  log[$.key]={log.do(level, $...)}
})

log.debug("invisible")

log.info("seen")
# 2026-12-31T23:59:59Z I ["seen"]

log.error("summary" details=[])
# 2026-12-31T23:59:59Z E ["summary" details=[]]

print={
  [kv=[sep=" " end="""

  """]]=$
  # $|pos|each({...})
}

print("a" "b")
# a b

print("a" "b" sep="" end="")
print("c")
# abc

input("sure? (yes/no): ")|case(
  "yes" {delete(all=true)}
  "no" {print("no problem")}
  else={print("assuming \"no\"")}
)

print(env.HOME)
# /home/me

# ./app.axol a -bc --d=e --foo
print(cli)
# ["./app.axol" "a" "-bc" "--d=e" b=true c=true d="e" foo=true]

[false null 0 "" [] {}]|each({
  print(bool($.val) not($.val))
})
# false true
# (6 times)

print(bool("anything else"))
# true

[eq ne lt gt lte gte and or]|each({
  print($.val(2 3) end=" ")
})
# false true true false true false 3 2

[sum sub mul div mod pow]|each({
  print($.val(3 2) end=" ")
})
# 5 1 6 1.5 1 9

a=["b" "c" "d" e="f"]
print(a.0 a[1 3] a.e a["e"] a["g" default="h"] end=" ")
# b ["c" "d"] f f h

print(a|del(1 3 default=[]))
# ["c" "d"]
print(a)
# ["b" e="f"]

a=1
{
  a=2
  print(a)
}()
# 2
print(a)
# 1

a=1
{
  up(a=2)
  print(a)
}()
# 2
print(a)
# 2

up(never=3)
# Error: `never` is not found

b=["a" c="d"]
b|up(c="e" f="g")
# Error: `f` is not found

b|add("h" i="j")
print(b)
# ["a" "h" c="d" i="j"]

b|add("k" "l" at=0)
print(b)
# ["k" "l" "a" "h" c="d" i="j"]

c=["d" e="f"]
g=["h" [i="j"] k="l"]
c|add(g flat=true)
print(c)
# ["d" "h" [i="j"] e="f" k="l"]

keys={$.0|map({$.key}))
print(["a" b="c"]|keys)
# [0 "b"]

vals={$.0|map({$.val}))
print(["a" b="c"]|vals)
# ["a" "c"]

h=["a" "b" "c" d="e" f="g"]

print(h|pos)
# ["a" "b" "c"]

print(h|kv)
# [d="e" f="g"]

print(
  h|len
  h|pos|len
  h|kv|len
)
# 5 3 2

print("abc"|find("c"))  # 2
print("abc"|find("d"))  # null

e=["a" "b" c="d"]
print(e|find("a"))  # 0
print(e|find("f"))  # null
print(e|find("d"))  # "c"

in={$.0|find($.1)|ne(null)}
print("a"|in(e))  # true
print("c"|in(e))  # false
print("c"|in(e|keys))  # true

e.$call={print("ok")}
e()
# ok

err=catch({
  print(1)
  throw("a" b="c")
  print(2)
})
# 1
print("finally")
# finally

print(err)
# ["a" b="c" $trace=12345]

print(err|trace([]))
# [
#   [path="/path/app.axol" line=42 col=1 at="e=catch({"]
#   [path="/path/app.axol" line=44 col=3 at="throw(\"a\" b=\"c\")"]
# ]

print(err|trace(""))
# /path/app.axol L42 C1
#   e=catch({
# /path/app.axol L44 C3
#   throw("a" b="c")

err2=catch({
  throw(err)
})
print(err2|eq(err))
# true

throw(err)
# /path/app.axol L42 C1
#   e=catch({
# /path/app.axol L44 C3
#   throw("a" b="c")
# Error: ["a" b="c" $trace=12345]

throw("one string only")
# Error: one string only

throw("anything" else="here")
# Error: ["anything" else="here"]

break={throw(break $...)}
continue={throw(continue $...)}
return={throw(return $...)}

# loop={
# each={
# map={
#   ...
#   err=catch(do)
#   err|then({
#     err.0|case(
#       break {...}
#       continue {...}
#       return {...}
#       else={throw(err)}

here={
  line=input()
  line|else(break)
  line|eq("skip")|then(continue)
  line|eq("ret")|then({
    return("ok" from=here)
  })
  print(line)
}
loop(here)|print
# (input "ret")
# ok

time=py.__import__("time")

# decorator
logged={
  [pos=[func] kv=[
    level=log.levels.debug
  ]]=$

  {
    args=$
    result=null

    start=time.time()
    err=catch({
      up(result=func(args...))
    })
    stop=time.time()

    log.do(level
      func=func
      args=args
      time=stop|sub(start)
      result=result
      err=err
    )

    err|then({err|throw})
    result
  }
}

foo=logged({
  something("slow" $...)
})

foo("bar")
# (logs the details)

a={$}
print(a("b" c="d"))
# ["b" c="d"]

e=[a={$}]
print(e.a("b" c="d"))
# ["b" c="d" $me=e]

rootType={[]}

type={
  [
    kv=[of=rootType]
    pos=[make=rootType]
  ]=$
  $type=[of... $of=of]
  $type.$call={
    parent=of($...)
    onlyMe=make($...)
    me=[of...]
    me|del("$call")
    me|add([
      parent...
      onlyMe...
      $parent=parent
      $type=$type
    ] flat=true)
    me
  }
  $type
}

Animal=type({[
  isAwake=true
  talk={
    $.$me.isAwake|then(return)
    throw("too sleepy")
  }
]})

Animal.getTypes={
  item=$.$me.$type|or($.$me)
  items=[]
  while({item|and(
    item|ne(rootType)
  )} do={
    items|add(item)
    up(item=item.$of)
  })
  items
}

Cat=type(of=Animal {
  [kv=[mood=2]]=$
  [
    mood=mood
    talk={
      $.$me.$parent.talk(
        $...
        $me=$.$me
      )
      print(["meow"]\
        |mul($me.mood)\
        |join(" ")
      )
    }
  ]
})

bob=Cat()

print(bob)
# [
#   getTypes={}
#   isAwake=true
#   mood=2
#   talk={}
#   $type=Cat
#   $parent=[
#     getTypes={}
#     isAwake=true
#     talk={}
#     $type=Animal
#     $parent=[]
#   ]
# ]

bob.talk()
# meow meow

bob.isAwake=false
bob.talk()
# Error: too sleepy

print(bob.$type|eq(Cat))
# true

print(bob.$parent.$type|eq(Animal))
# true

print(bob|is(Cat))
# true

print(bob|is(Animal))
# true

print(Cat|is(typeOf=Animal))
# true

Lion=type(of=Cat)
simba=Lion(mood=1)

print(simba.getTypes())
# [Lion Cat Animal]

print(Lion.getTypes())
# [Lion Cat Animal]

File=type({
  [pos=[path] kv=[mode="r"]]=$
  file=[]
  file.handle=fs.open(path mode)
  ["write" "read" "seek" "truncate"]|each({
    action=$.val
    file[action]={
      fs[action]($.$me.handle $...)
    }
  })
  file.$close={
    fs.close($.$me.handle)
  }
  file
})

with={
  [pos=[do] rest=[items]]=$
  result=null
  err=catch({
    up(result=do(items...))
  })
  items|each({$.val.$close()})
  err|then({err|throw})
  result
}

with(
  input=File("input.txt" mode="r")
  result=File("result.txt" mode="w")
{
  $.input.read()|$.result.write
  throw("test err")
})
# (both files are auto-closed)
# Error: test err

seq={
  [pos=[start stop] kv=[step=1]]=$
  i=start
  cmp=if(step|gte(0)
    then={lte}
    else={gte}
  )
  while({i|cmp(stop)} do={
    msg=pause(i)
    msg.restart|ne(null)|then({
      up(i=msg.restart)
      continue()
    })
    up(i=i|sum(step))
  })
}

a=seq(1 3)
print(a)
# [$next={}]

print(a.$next())
# 1

print(a.$next())
# 2

print(a.$next(restart=2))
# 2

print(a.$next())
# 3

err=catch({
  print(a.$next())
})

print(err.0|eq(pause))
# true

print(err.result)
# 4

each={
  [pos=[items do]]=$
  items.$next|then({
    loop({
      item=null
      err=catch({
        up(item=items.$next())
      })
      err|then({
        err.0|eq(pause)|then(break)
        throw(err)
      })
      do(val=item)
    })
    return(from=each)
  })
  # ...
}

seq(1 100)|each({print($.val)})
# 1
# 2
# ...
# 100

tasks=[]

Task=type({
  [pos=[func] rest=[args]]=$
  task=[result=null]
  task.err=catch({
    task.result=func(args...)
  })
  task.done=bool(task.err)|or(not(
    task.result.$next
  ))
  task.done|else({tasks|add(task)})
  task
})

# This is the main loop,
# which executes all tasks,
# including `mainTask` auto-created
# from the main code of the app.
mainLoop={
  while({tasks} do={
    tasks|each({
      key=$.key
      task=$.val
      task.done|then({
        tasks|del(key)
        continue()
      })
      err=catch({
        task.result.$next()
      })
      err|else(continue)
      if(err.0|eq(pause)
        then={
          task.result=err.result
          if(task.result.$next
            then=continue
          )
        }
        else={
          task.result=null
          task.err=err
        }
      )
      task.done=true
      tasks|del(key)
    })
  })
}

task=Task(seq 1 3)

print(task)
# [
#   done=false
#   result=[$next={}]
#   err=null
#   $type=Task $parent=[]]

pause()
# (mainTask.result.$next() returns
# to mainLoop, which checks other tasks,
# and then calls mainTask.result.$next() again,
# so this pause() returns here)

print(task)
# [done=true result=4 err=null
# $type=Task $parent=[]]

f={
  print($.0)
  42
}
instant=Task(f "ok")
# ok

print(instant)
# [done=true result=42 err=null
# $type=Task $parent=[]]

await={
  [kv=[done=null err=1 ok=null]]=$
  need=[done=done err=err ok=ok]
  have=[done=0 err=0 ok=0]

  tasks=[]
  $|pos|each({
    task=$.val
    task|is(Task)|else({
      throw("not Task: {task}")
    })
    tasks|add(task)
  }]

  do={
    tasks|each({
      key=$.key
      task=$.val

      task.done|then({
        have.done=have.done|sum(1)
        if(
          need.done|ne(null)|and(
          have.done|gte(need.done))
          then={break(from=do)}
        )

        if(task.err
          then={
            have.err=have.err|sum(1)
            if(
              need.err|ne(null)|and(
              have.err|gte(need.err))
              then={task.err|throw}
            )
          }

          else={
            have.ok=have.ok|sum(1)
            if(
              need.ok|ne(null)|and(
              have.ok|gte(need.ok))
              then={break(from=do)}
            )
          }
        )

        tasks|del(key)
        continue()
      })
      pause()  # let mainLoop work
    })
  }
  while({tasks} do=do)

  if($|len|eq(1)
    then={$.0.result}
    else={null}
  )
}

one=Task(seq 1 10)
another=Task(seq 2 20)
await(one another)

print(one.done another.done)
# true true

print(one.result another.result)
# 11 21

result=await(Task(seq 3 30))
print(result)
# 31

bad=Task(seq 4 40 step={})
print(bad)
# [
#   done=false
#   result=[$next={}]
#   err=null
#   $type=Task $parent=[]]

await(bad)
# (trace to seq)
#   up(i=i|sum(step))
# Error: cannot sum(4 {})

async={
  func=$.0
  {Task(func $...)}
}

aseq=async(seq)

print(await(aseq(5 50)))
# 51

afoo=async({
  # foo
})

About

Minimalist programming language simple to read, write, extend

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published