Forget about &&, ||, and !.
Embrace the elegance of Do: a minimalist language
that replaces symbols with the clarity of plain English.
Everything you need to write Do programs.
print "Hello World"go count = 10
go price = 12.5
go name = "John"
go active = true
go empty = null
go list = [1, 2, 3]
go person = {"name": "John", "age": 30}go declares a mutable variable. let declares an immutable constant.
go age = 4
age = 2 note works fine
let pi = 3.14
pi = 4 note Runtime Error: Cannot reassign a let valueIdentifiers: lowercase start, camelCase, letters and digits only. Kind names use PascalCase.
| Valid | Invalid |
|---|---|
player1 | Player (reserved for kinds) |
userScore | my_score |
checkPerson | 2age |
ask always returns a string. F-strings evaluate expressions inside {}.
go name = ask "Enter your name:"
print f"Hello, {name}"
go x = 5
go y = 0 minus 2
print f"Result: {x plus y}" note Result: 3| Operation | Keyword |
|---|---|
| Addition | plus |
| Subtraction | minus |
| Multiplication | times |
| Division | over |
| Modulus | mod |
| Exponent | exp |
The - symbol is for negation only. Use minus for subtraction.
go x = -5 note negative literal
go a = 10
print -a note -10 (negation)
go y = -a plus 3 note -7
go z = 5 - 3 note ERROR: use 'minus'plus concatenates. times repeats.
print "Hello" plus "World" note HelloWorld
print "do" times 3 note dododoprint 5 is 5 note true
print 5 isNot 2 note true
print 10 above 8 note true
print 3 below 8 note true
print 10 atLeast 10 note true
print 2 atMost 3 note true
print true and false note false
print true or false note true
print not false note trueNon-empty strings are truthy. Empty strings are falsy.
go age = 19
if age below 13
print "Child"
otherwise age below 18
print "Teen"
else
print "Adult"
endIfgo numbers = [1, 2, 3]
for number in numbers
print number
endForgo x = 0
while x below 5
print x
x = x plus 1
endWhileskip continues to the next iteration. stop breaks out of the loop.
Declare with do, return with give, pass arguments with with and and.
do checkPerson with name and age
if name is "John" and age is 30
print true
else
print false
endIf
endDo
checkPerson with "John" and 30Call with no arguments: myFunc()
go fruits = ["apple", "banana"]
print fruits at [0] note apple
fruits.push["cherry"]
fruits.pop[]| Method | Description |
|---|---|
.max[].min[] | Maximum / minimum |
.sum[] .avg[] | Sum / average |
.sort[] | Sort ascending |
.reverse[] | Reverse order |
.Join[sep] | Join into string |
.Shuffle[] | Random shuffle |
.clear[] | Remove all elements |
let user = {"name": "Alice", "lv": 5}
print user.name note Alice
go player = {"hp": 100}
player.hp = 80go hello = "hello"
print hello.length[] note 5
print hello.split[] note ["h", "e", "l", "l", "o"]
print hello.contains["h"] note truePostfix operators. Can be chained.
print "42" toInt note 42
print 3.14 toStr note 3.14
print "3.14" toFloat note 3.14
print 1 toBool note true
print "42.9" toFloat toInt note 42
print typeOf("hello") note string
print typeOf(42) note integergo val = random from 0 to 500 with 3 digits
go whole = random from 1 to 10 with 0 digitsnote This is a single-line comment
note
This is a multi-line comment
It spans multiple lines
endNoteReusable structures with properties and methods. Names use PascalCase.
kind Person with name and age
endKind
go john = new Person with "John" and 32
print john.name note Johnkind Square with l and w
do getArea
give this.l times this.w
endDo
endKind
go sq = new Square with 5 and 10
print sq.getArea() note 50kind Animal with name
endKind
kind Rabbit extends Animal
do speak
print f"I am {this.name}"
endDo
endKind
go bunny = new Rabbit with "Bugs"
bunny.speak() note I am BugsChild kinds inherit all parent methods and can override them.
async do getData with url
go response = await fetch with url
give response.body
endDo
go data = await getData with "https://api.example.com/data"fetch returns {"status": 200, "ok": true, "body": ...}. JSON auto-parses.
go options = {
"method": "POST",
"headers": {"Content-Type": "application/json"},
"body": {"name": "John"}
}
go res = await fetch with "https://api.example.com/users" and optionsgo val = 100
go result = val above 50 when true "big" otherwise "small"
print result note bigexport let PI = 3.14159
export do square with n
give n times n
endDo
from "math_utils.do" import PI and squareFormal grammar and token reference for the Do language.
program = { statement } EOF ;
statement = simpleStatement NEWLINE
| blockStatement ;
simpleStatement = printStmt
| varDecl
| assignment
| funcCall
| returnStmt
| loopControl
| importStatement
| exportStatement
| comment ;
blockStatement = ifStmt
| forStmt
| whileStmt
| funcDecl
| kindDecl
| multiLineComment ;
printStmt = "print" expression ;
varDecl = ("go" | "let") identifier "=" expression ;
assignment = ( identifier | thisExpr | memberAccess ) "=" expression ;
expression = askExpr | ternaryExpr | logicExpr ;
askExpr = "ask" string ;
ternaryExpr = logicExpr "when" "true" expression
"otherwise" expression ;
logicExpr = comparisonExpr
{ ("and" | "or") comparisonExpr } ;
comparisonExpr = mathExpr
[ comparisonOp mathExpr ] ;
comparisonOp = "is" | "isNot" | "above" | "below"
| "atLeast" | "atMost" ;
mathExpr = term { ("plus" | "minus") term } ;
term = factor { ("times" | "over" | "mod") factor } ;
factor = unary [ "exp" factor ] ;
unary = [ "not" | "-" ] postfix ;
postfix = primary { conversionOp } ;
conversionOp = "toStr" | "toInt" | "toFloat" | "toBool" ;
primary = literal | identifier | funcCall | randomCall
| indexAccess | methodCall | propertyAccess
| list | catalog | fString | newExpr
| awaitExpr | fetchExpr | thisExpr | typeOfExpr
| "(" expression ")" ;
literal = INTEGER_LITERAL | FLOAT_LITERAL | STRING_LITERAL
| BOOLEAN_LITERAL | NULL_LITERAL ;
list = "[" [ expression { "," expression } ] "]" ;
indexAccess = identifier "at" "[" expression "]" ;
catalog = "{" [ pair { "," pair } ] "}" ;
pair = string ":" expression ;
propertyAccess = expression "." identifier ;
methodCall = expression "." methodName
( "[" [ expression { "," expression } ] "]"
| "(" ")"
| "with" expression { "and" expression } ) ;
methodName = "push" | "pop" | "max" | "min" | "avg" | "sum" | "sort" | "shuffle" | "clear" | "reverse" | "join" | "split" | "contains" | "length" ;
randomCall = "random" "from" expression "to" expression
"with" expression ("digit" | "digits") ;
fString = "f" string ;
typeOfExpr = "typeOf" "(" expression ")" ;
funcDecl = [ "async" ] "do" identifier
[ "with" identifier { "and" identifier } ]
NEWLINE { statement } "endDo" ;
funcCall = identifier
( "(" ")"
| "with" expression { "and" expression } ) ;
returnStmt = "give" expression ;
ifStmt = "if" expression NEWLINE
{ statement }
{ "otherwise" [ expression ] NEWLINE { statement } }
[ "else" NEWLINE { statement } ]
"endIf" ;
forStmt = "for" identifier "in" identifier NEWLINE
{ statement }
"endFor" ;
whileStmt = "while" expression NEWLINE
{ statement }
"endWhile" ;
loopControl = "skip" | "stop" ;
kindDecl = "kind" KIND_NAME [ "extends" KIND_NAME ]
[ "with" identifier { "and" identifier } ]
NEWLINE { funcDecl } "endKind" ;
newExpr = "new" KIND_NAME
[ "with" expression { "and" expression } ] ;
thisExpr = "this" "." identifier ;
awaitExpr = "await" expression ;
fetchExpr = "fetch" "with" expression
[ "and" expression ] ;
importStatement = "from" string "import" identifier { "and" identifier }
| "import" string "as" identifier ;
exportStatement = "export" ( varDecl | funcDecl ) ;
comment = "note" [ noteText ] ;
multiLineComment = "note" NEWLINE { noteText } "endNote" ;
identifier = lowercaseLetter
{ lowercaseLetter | uppercaseLetter | digit } ;
KIND_NAME = uppercaseLetter
{ lowercaseLetter | uppercaseLetter | digit } ;