Mercurial > repos > other > SevenLanguagesInSevenWeeks
view 2-Io/day3-DSL.io @ 46:eac30c1b92da
Add more notes and try to understand the operators
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Wed, 20 Sep 2017 20:48:37 +0100 |
parents | 8a2451a7b86e |
children | 409249712590 |
line wrap: on
line source
# Creating a simple "domain-specific language" # (Except it's not really - it's just a little extension to support # the "{ key:value[, key:value[…]] }" format of specifying dictionaries) # Because this is a string then we can do it at any time! OperatorTable addAssignOperator(":", "atPutThing") # curlyBrackets is an automatically invoked function from the parser whenever # it encounters curly brackets. # This is hidden black magic that you need to know about to override it. # It appears to call the method for all of the content within the brackets. curlyBrackets := method( # Create a map map := Map clone # Foreach arg that got passed (each comma-separated line within the brackets) # then run that on the map # Note: It isn't clear why ":" operates on the map at this point # The book says "we'll execute `map atPutThing(a, b)`" but why? # Colon was originally on a string, not the map, so how does it know to invoke on the map? call message arguments foreach(arg, # Based on the following println then it is already "atPutThing(a, b)" by this point # but the ordering still doesn't make sense. # See also http://iolanguage.org/guide/guide.html#Syntax-Operators # # It *might* be a side-effect of how addAssignOperator works and then the map hijacks # the values, but that isn't clear from the book OR the documentation! #arg println map doMessage(arg) ) # Return the map (last line's return is the return) map ) Map atPutThing := method( # Call the standard method self atPut( # And pull the call args to pass through # NOTE: arg 1 has its quotes stripped automatically because it's a number # or some other magic! call evalArgAt(0) asMutable removePrefix("\"") removeSuffix("\""), call evalArgAt(1) ) ) # Note: Trailing commas break things in COMPLETELY CRYPTIC WAYS # This is because we use doString, which executes it as a program, # BUT the stack trace doesn't make this clear, so you end up chasing # bugs in ENTIRELY THE WRONG PART OF THE CODE. # Eval considered harmful. the_string := "{ \"foo\": \"12345\", \"bar\": \"7890\" }" phoneNumbers := doString(the_string) phoneNumbers keys println phoneNumbers values println # It feels like implementing something like this should work, # but it doesn't because "Number does not respond to ':'" # because we assigned ":" as an assignment operator (like :=) # and not as a normal operator, although it's then EVEN LESS CLEAR # how the code in curlyBrackets works # Also, Io Language docs are poor and don't make it clear how to: # a) define a range that works; or # b) do ANYTHING with the OperatorTable Number atPutThing := method( call println return Range (call target) to(call evalArgAt(1)) ) # But presumably this will break, because there's no "atPutThing" method a := 1 b := 5 range := a : b # Yep - "Exception: Number does not respond to ':'" # So you've got to be careful for reusable operators