tutorial.attl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #!/usr/bin/env attl
  2. #
  3. # Welcome to ATTL! This is an executable tutorial for the ATTL language.
  4. # You will need to get the ATTL interpreter and install it for your platform
  5. # to run this script.
  6. # What is the line on top of the script? It is there to allow the ATTL script
  7. # to be executed directly on Unix like OS.
  8. #
  9. # Attl works in two phases: parse and evaluate.
  10. #
  11. # In the parse phase ATTL reads in the script and parses it,
  12. # which means it breaks it down into a format it can interpret. If an error
  13. # occurs in this phase, ATTL will report that error and the script will
  14. # do nothing at all.
  15. #
  16. # In the evaluate phase, ATTL then interprets or evaluates the parsed script.
  17. # If an error occurs the script will still partially be executed,
  18. # and such errors may be caught and handled.
  19. #
  20. # Now let's start exploring the ATTL language itself.
  21. # In front of this line and those above, you can see there is a # mark.
  22. # This is to indicate that the line is a comment.
  23. # ATTL parses comments but they do nothing during evaluation.
  24. # This is useful to explain what an ATTL script does like in this tutorial.
  25. #
  26. # Comments run from the # mark until the end of the line.
  27. # Comments may also be indented with spaces.
  28. # For example: this is also comment
  29. #
  30. # To make ATTL actually do something, we need to write a command in the script.
  31. # Let's start with the traditional "Hello World!" below:
  32. print "Hello World!\n"
  33. # The command above consists of an order print, and it's parameter
  34. # "Hello world\n" which is a literal text, with a new line character in it at
  35. # the end.
  36. # This commands orders the ATTL interpreter to print the text "Hello World"
  37. # followed by a new line to the interpreter's standard output.
  38. #
  39. # Commands in ATTL consist of an order followed optionally by parameters
  40. # Every parameter has to have whitespace in front of it, so ATTL can find it.
  41. # That's why it's not allowed to have whitespace at the end of the line.
  42. # Attl will give a parse error since it expects a parameter to follow the space.
  43. # An Attl command must be terminated by a newline or a semicolon.
  44. print "Hello " ; print "World!\n"
  45. # Some arguments take multiple parameters.
  46. # For example, print can also take multiple parameters.
  47. print "Hello $1\n" "World!"
  48. #
  49. # The $1 in the string above is an example of string interpolation.
  50. # This is explained later, below in this tutorial. For now, note that
  51. # print will replace $1, $2, ... with the text representation of it's 1st,
  52. # 2nd, and so forth parameter.
  53. #
  54. # All commands in ATTL have this same form. Unlike many other programming
  55. # languages, there are no special constructs. The evaluation of an Attl script
  56. # is fully determined by the available commands.
  57. # In this tutorial we look at how ATTL works with the builtin commands it
  58. # provides, but when ATTL is used as an embedded language, it might work
  59. # differently if the commands are different or not available.
  60. #
  61. # The effect of ATTL commands also depend on the Environment in which they
  62. # are executed. ATTL command can write to the ATTL environment's output,
  63. # read from the ATTL's environment input, and store data in the environment
  64. # using variables. Variabes are described later.
  65. #
  66. # Let's continue with some examples of commands.
  67. # For example this is how do do 1 + 2 in ATTL:
  68. iadd 1 2
  69. # As you can see attl has no operators, just commands, so we use the command
  70. # iadd, short for integer add to add 1 and 2 together.
  71. # You will notice that when running this script, this iadd seems to do nothing
  72. # This is because we don't print the value anywhere.
  73. # Let's see how to do this.
  74. print "1+2=$1\n" [iadd 1 2]
  75. # The command above prints 1+2=3. But, what are the square brackets [] for?
  76. # Let's see what happens when we remove them:
  77. print "1+2=$1\n" iadd 1 2
  78. # Then the command prints 1+3=iadd
  79. # The brackets [] are to indicate to ATTL that it should not take what is
  80. # between them as parameters of the first command in the line, but that it
  81. # starts a new command of which the value should be taken and used as
  82. # a parameter. Such a command between [] is called an Evaluation.
  83. #
  84. # Evaluations are eagerly evaluated when they are in an argument list.
  85. # This means they are evaluated before the command receives them as arguments.
  86. #
  87. # Evaluations may be nested as much as you like. For instance:
  88. print "((5+4)*3)-1)/2=$1\n" [idiv [isub [imul [iadd 5 4] 3] 1] 2]
  89. # .. prints ((5+4)*3)-1)/2=13
  90. #
  91. # While this seems a bit cumbersome compared to operators, it keeps ATTL simple.
  92. # I do not recommend using ATTL for intensive maths.
  93. #
  94. # From this we can see that attl commands not only have effects such as writing
  95. # to the output, they also produce a result. If the ATTL command is successful
  96. # it returns a Value. If it not successful, it fails, which causes execution to
  97. # end, unless a rescue command is used (see later).
  98. # All commands either return a value or fail. Even print returns the amount of
  99. # bytes written, as follows:
  100. #
  101. print "Written $1 bytes\n" [print "Hello World\n"]
  102. #
  103. # The basic data which ATTL operates on, and which commands return
  104. # is called a Value. Unlike languages like TCL, ATTL Values are typed.
  105. # To see the type of a value use the typeof command
  106. print "type of 1: $1\n" [typeof 1]
  107. print "type of \"hi\": $1\n" [typeof "hi"]
  108. #
  109. # ATTL supports the following types by default:
  110. # * String: for literal text, in UTF-8 format.
  111. write "String µ出来る\n"
  112. # The above should write String µ出来るif your terminal supports it.
  113. # Normal strings support the following escape sequences:
  114. # \a: bell character
  115. # \b: backspace character
  116. # \e: escape character
  117. # \f: form feed character
  118. # \n: new line character
  119. # \r: carriage return character
  120. # \t: tab character
  121. # \\: a \ character
  122. # \": a " character
  123. # For instance, on a terminal which suports ANSI color the following prints
  124. # foo bar\ in red:
  125. print "escapes: \nX\b\e[31mfoo\tbar\\\e[0m\n\r"
  126. # Strings can run over multiple lines
  127. # A string can also run over multiple lines if it is a raw string between ``
  128. # Raw strings accept no escape characters and always terminate on a `.
  129. # There is no way to put a `in a raw string, but a raw string ans a normal
  130. # string can be appended to each other to allow this if the sadd
  131. # command is available.
  132. print `A
  133. "raw"
  134. string
  135. \\ no escapes \"
  136. `
  137. # * Int: which is for integer numbers.
  138. print "Int: $1\n" 123
  139. # * Word: which is for names.
  140. # Words consist have any non-symbol, non whitespace character, _ and /
  141. print "Word: $1\n" iAmA_Word/7
  142. # * Bool: for boolean values. $true and $false are default boolean variables.
  143. # Words consist have any non-symbol, non whitespace character, _ and /
  144. print "Bool: $1 $2\n" $true $false
  145. # * List: for lists of ATTL values.
  146. # lists are created wth the list command
  147. print "List: $1\n" [list 1 2 3]
  148. # * Map: for a lookup map by string to value.
  149. # maps are created wth the map command. The key of maps must be strings.
  150. print "Map: $1\n" [map "a" 1 "b" 2]
  151. # * Block: for blocks of ATTL commands, between {}.
  152. # More about blocks later.
  153. print "Block: $1\n" {print "block ";print "world"}
  154. # * Type: for types.
  155. # Types can be defined with the command type. they are useful for defining
  156. # overloads. More on overloads later.
  157. print "Type: $1\n" [typeof [type "Type"]]
  158. #
  159. # When embedding ATTL, the embedding program can define other types.
  160. #
  161. # We can store values the ATTL environment as variables.
  162. # In ATTL, a variable must first be declared and initialized with let
  163. # before using it.
  164. #
  165. print "Hello $1 variable\n" $variable
  166. # This prints Hello !nil because the variable has not been defined yet.
  167. # To define a variabe with a value, use let
  168. let variable "World"
  169. # To get the value of the variable use get in an evaluation:
  170. print "Hello Variable: $1\n" [get variable]
  171. # [get variablename] is a common operation so we can abbreviate it using
  172. # a dollar sign: $variablename
  173. print "Hello Variable: $1\n" $variable
  174. # It's possible to repeat the dollar sign for indirect variable expansion
  175. let name variable
  176. print "Hello indirect variable: $1\n" $$name
  177. # String interpolation.
  178. # print as a command, performs string interpolation. That means it looks for
  179. # any dolar signs in the text and replaces them with the value of the
  180. # following variable in the ATTL environment.
  181. print "Hello Variable: $variable\n"
  182. # The variable for interpolation can also be indicated by a ${variable}
  183. # This is useful to if the variable must befollowed by a non-space:
  184. print "Hello Variable: ${variable}Record\n"
  185. # To obtain a $ in an interpolated value, just double it.
  186. print "Hello dollar: $$${1}\n" 35
  187. # ATTL does not do string interpolation automatically, it is up
  188. # to the commands that take strings to do this if needed.
  189. # To interpolate strings ourselves, we can use the expand command
  190. set variable "expanded"
  191. let expanded [expand "Hello $variable\n"]
  192. print $expanded
  193. # Blocks are lists of commands. Block are not evaluated when passed as
  194. # a parameter to a command, but passed as such, and can be used to
  195. # implement flow control using commands, or to define new commands.
  196. # Blocks can run over multiple lines, the newlines in a block do NOT
  197. # terminate the top level command in front of the block.
  198. # The value of executing a block is set by the last command in the block,
  199. # or the return command if present.
  200. # Blocks also have anonymous parameters that are evaluated upon execution
  201. # of the block.
  202. let block {
  203. # Blocks receive their anyonymous parameters in $1..$argc, and
  204. # as a list in $argv
  205. let p1 $1
  206. print "hello $p1 $argc $argv"
  207. print " block\n"
  208. return 77
  209. }
  210. # Blocks stored in variables can be executed as if they were commands,
  211. # and can take parameters
  212. block "param1"
  213. # And blocks evaluate to their last command or return statement.
  214. print "block value: $1\n" [block]
  215. # Variables are dynamically and block-scoped.
  216. # When using set, and get, the innermost variable defined with let
  217. # will be used to set or get the value.
  218. # XXX bug here it seems
  219. let foo 1
  220. #{
  221. # let foo 2
  222. # {
  223. # let foo 3
  224. # print "$foo\n"
  225. # }
  226. # print "$foo\n"
  227. #}
  228. print "$foo\n"
  229. # compare the above with the below:
  230. let bar 1;{set bar 2;{set bar 3;print "$bar\n"};print "$bar\n"};print "$bar\n"
  231. # You can define commands yourself with the builtin "to" command.
  232. # This allows you to use named parameters in the block.
  233. # Parameters are passed by value, but using word parameters, you can implement
  234. # pass by name parameters as well.
  235. to set_print name value {
  236. print "Setting $name from $1 to $value\n" $$name
  237. set $name $value
  238. return 0
  239. }
  240. let quux 123
  241. set_print quux 321
  242. print "quux: $quux\n"
  243. # Flow control can be done with the built in if command.
  244. if [igt $quux 200] {
  245. print "OK\n"
  246. } else {
  247. print "HUH?\n"
  248. }
  249. # ...or with the switch comand. The default word is used to mark the default
  250. # block. Other values are compared by string equality.
  251. switch $quux default {
  252. print "NOK?\n"
  253. } 123 {
  254. print "ALSO NOT OK\n"
  255. } 321 {
  256. print "OK\n"
  257. }
  258. # The overload command allows you to use the same command for different types
  259. # by redirecting them to a type-specific command
  260. overload add iadd Int Int
  261. overload add sadd String String
  262. print [add 10 20]
  263. print [add "10" "20"]
  264. # When an error occurs, it can be caught by setting up a rescue block with
  265. # the rescue command. The rescue block itself has block scope, that is
  266. # it applies to the block in which the rescue command is called.
  267. # To cause an error, use the fail command.
  268. to rescue_fail {
  269. rescue {
  270. let e $1
  271. print "Error rescued: $e\n"
  272. }
  273. fail "Synthetic error"
  274. }
  275. rescue_fail
  276. # There are many other builtin commands available. See their description
  277. # by using the help or help all command.
  278. # help all
  279. help help