*** hashmal has quit IRC | 00:02 | |
*** mkroehnert has quit IRC | 02:08 | |
*** gatesphere has joined #io | 02:24 | |
prologic | hey jer u around? | 02:30 |
---|---|---|
*** gatesphere has quit IRC | 03:07 | |
prologic | https://pypi.python.org/pypi/mio-lang/0.0.6 | 06:07 |
*** OpenSpace has quit IRC | 07:58 | |
*** mkroehnert has joined #io | 08:09 | |
*** OpenSpace has joined #io | 08:11 | |
*** hashmal has joined #io | 09:45 | |
*** fredreichbier has joined #io | 11:31 | |
*** fredreichbier has quit IRC | 13:14 | |
*** gatesphere has joined #io | 13:47 | |
jer | yeah i'm around | 14:38 |
jer | prologic, your first example should really be like this: Number fact := method((1..self) reduce(0, a, n, a * n)) =D | 14:40 |
jer | btw, in terms of your goal of implementing coroutines; you can simulate coroutines by defining a simple scheduler which maintains a queue of continuations. you add a continuation to this queue, and pop another one off when you're ready to run | 14:57 |
jer | it's very naive, but gets you to a place to start =] | 14:57 |
prologic | and this would avoid the recursion limit I'm having as well no doubt? | 15:04 |
jer | depends... you could implement reduce/foldl iteratively, which yes, would avoid the recursion limit you've got | 15:09 |
prologic | yeah well at the moment my message evalulator can call an activateable block/method or a continatuion which in trun calls the evaluator | 15:11 |
prologic | you acn see how th C stack gets exceeded :) | 15:11 |
prologic | in general couldn't I just process all messages in a queue with a running schedular? | 15:12 |
jer | you could | 15:12 |
jer | that's generally how i'd go about implementing a run loop | 15:12 |
prologic | *nods* | 15:14 |
prologic | I think I might do that at some stage | 15:14 |
prologic | also re your example above | 15:14 |
prologic | I _could_ rewrite the example like this | 15:14 |
prologic | almost (I think) | 15:14 |
prologic | I already have Range and .. syntax and a reduce builtin function | 15:14 |
prologic | I'll have to see if I can :) | 15:14 |
jer | oh that's another thing, i would avoid builtins in mio | 15:15 |
jer | if you want to be able to call them from a python ffi, that's one thing | 15:16 |
jer | but i wouldn'tm ake them in an io directly | 15:16 |
jer | instead what i'd do, is define traits for this purpose | 15:16 |
prologic | oh I am | 15:17 |
prologic | but also builtins (simple functions) | 15:17 |
jer | yeah what i'ms aying is ignore the builtins, implement those as traits instead | 15:19 |
jer | "builtins" don't really make sense in an io like language | 15:20 |
jer | which has only local state objects | 15:20 |
jer | io objects are basically just N-way trees | 15:20 |
jer | you start from the Lobby (though there's a duality between Object and Lobby that's not entirely representable by this idea) | 15:20 |
jer | and then work your way down | 15:20 |
jer | it's all local, there is no global state | 15:21 |
jer | so there's no real place where a builtin can live and it 'make sense' | 15:21 |
prologic | hmm | 15:23 |
prologic | I'm so heavily influenced by python :) | 15:23 |
prologic | I like to write: print("foo") | 15:24 |
prologic | instead of "foo" print() | 15:24 |
prologic | heh | 15:24 |
prologic | btw is there a straight forward way to reshuffle the message chain for operator precedence? | 15:24 |
prologic | everytime I've tried this I've failed | 15:25 |
jer | what you can do | 15:30 |
jer | is maintain a map of operator -> priority level | 15:30 |
jer | and just run it against the token stream | 15:30 |
jer | insert ( and ) at the appropriate spots | 15:30 |
jer | that's what io's operator table stuff does | 15:30 |
prologic | hmm | 15:31 |
jer | the way you can do that is you read ahead in the token stream | 15:32 |
jer | for where to place the ) | 15:32 |
jer | if you come across an equal or lower priority token name, insert a ) | 15:32 |
jer | if you come across a token with a higher level, insert another ( and remember you need to place two )'s | 15:32 |
jer | do this over the token stream before you evaluate | 15:33 |
jer | all will be will | 15:33 |
jer | all will be well | 15:33 |
prologic | hmm I see | 15:34 |
jer | there's no reason that in a less naive approach you couldn't start evaluating when you've balanced the () level at 0 | 15:37 |
jer | i.e., no more need to insert a ) | 15:38 |
jer | so you could do parsing concurrently while evaluating | 15:38 |
jer | you'd have ot maintain some kind of barrier though so the evaluation didn't overtake the parsing | 15:38 |
jer | i.e., block the mutator until another chunk of the message tree is available to be evaluated | 15:38 |
jer | it inserts pauses in the running program, but at least it's not a giant pause at the start | 15:38 |
jer | (keep in mind, when i say giant, i'm talking about milliseconds, not seconds) | 15:39 |
jer | so mutator pauses, if any inline with evaluation, shouldn't be more than a few milliseconds tops; as opposed to say 100 ms tops at the start of evaluation the naive way | 15:39 |
prologic | http://codepad.org/awPU3KmN | 15:51 |
prologic | almost there :) | 15:51 |
prologic | few bugs | 15:51 |
prologic | hmm | 15:58 |
prologic | >>> x = parse("1 + 2 * 3 + 4") | 15:58 |
prologic | >>> x | 15:58 |
prologic | 1 +(2 *(3 +(4))) | 15:58 |
prologic | not quite right there | 15:58 |
prologic | I expect 1 +(2 *(3)) + 4 | 15:59 |
jer | yeah so you have to keep track of all of the precedence levels you've hit; and their indexes | 15:59 |
prologic | oh? | 16:00 |
prologic | hmm | 16:00 |
prologic | can you elaborate on what needs to happen? | 16:00 |
prologic | keep a stack of levels? | 16:00 |
jer | alright so, think of it like two stacks | 16:00 |
prologic | and push/pop the stack? | 16:00 |
jer | a stack of tokens | 16:00 |
jer | actually let me rephrase | 16:00 |
jer | a stream of tokens, and an index stack | 16:01 |
jer | when you go to insert a ) in the token stream, you pop the index off the stack, then look ahead, and see if the next token is >= the last token's precendence level, and keep inserting ) until it's >= last precedence | 16:01 |
jer | err until it's greater than; not >= | 16:02 |
prologic | http://codepad.org/sjtZQdNt | 16:13 |
prologic | this seems to work | 16:13 |
prologic | am I missing anything? | 16:13 |
jer | test it out the ass | 16:14 |
jer | every type of expression you can think of from simple to annoyingly complicated | 16:14 |
jer | have calls to methods in there too, malformed parse trees | 16:14 |
prologic | hmm no it's still wrong | 16:14 |
jer | remember that giving good locations of errors is REALLY HARD in io | 16:15 |
prologic | tell me about it :) | 16:15 |
prologic | I have basic stack traces now | 16:15 |
prologic | but they suck/ugly | 16:15 |
prologic | they're helpful but not nearly enough | 16:15 |
prologic | hmm | 16:16 |
prologic | seems I'm not quite getting the last bit you said | 16:16 |
prologic | when you go to insert a ) in the token stream, you pop the index off the stack, then look ahead, and see if the next token is >= the last token's precendence level, and keep inserting ) until it's > last precedence | 16:16 |
jer | nono sorry, all instances of >= should be > | 16:16 |
jer | so given an expression like: | 16:17 |
jer | 1 + 2 * 4 / 2 + 7 - 1 * 4 | 16:17 |
jer | you'd expect that to parse like this: | 16:17 |
jer | 1 +(2 *(4) /(2)) +(7) -(1 *(4)) | 16:17 |
jer | when you encounter the first + | 16:17 |
jer | your level is 0 | 16:17 |
jer | let's say + lives at level 3 | 16:18 |
jer | then you have a stack of levels: 3 0 | 16:18 |
jer | where 3 is at the top | 16:18 |
jer | ypu push a ( into the stream | 16:18 |
jer | after + | 16:18 |
jer | and continue reading on | 16:18 |
jer | you peek at the top of the stack when you encounter the next token 2, it's not in the op table, so you continue, then the next token is a * | 16:18 |
jer | it's in the op table at level of say 4 | 16:18 |
jer | so you push 4 onto the stack, insert another ( | 16:19 |
jer | look ahead, you see 4 which is < the top of the levels stack | 16:19 |
jer | so you add a ) | 16:19 |
jer | you look ahead, see / which is > the top of the stack (3) so you insert a ( after it | 16:19 |
jer | next token is 2, which is level 0, and less than 3 | 16:19 |
jer | err less than 4 | 16:19 |
jer | since / is 4 | 16:19 |
jer | so you pop 4 from the stack, insert a ) | 16:19 |
jer | then you look ahead, see that + is euqal to 3, so you add another ) before + | 16:20 |
jer | so now your level stack has one item, 0 | 16:20 |
prologic | ahh | 16:20 |
jer | it could even be empty | 16:20 |
prologic | I think I get it | 16:20 |
jer | clearer? | 16:20 |
prologic | much :) | 16:20 |
jer | btw, the above algorithm is not tested, and i have not proven it correct formally =] | 16:20 |
jer | i would seriously write a shit ton of tests against your parser | 16:23 |
jer | it's your language's user interface | 16:23 |
jer | it's gotta be right | 16:23 |
jer | developers are more forgiving of library bugs than parser bugs | 16:23 |
*** fredreichbier has joined #io | 16:24 | |
prologic | *nods* | 16:25 |
jer | prologic, every single way you can think of; including missing ) | 16:25 |
prologic | mio has over 250+ unit tests atm | 16:25 |
jer | i.e., dev writes 1 + 2 * (1 + 3 | 16:25 |
jer | ah cool | 16:25 |
prologic | *nods* | 16:25 |
prologic | I'm not even close to rewriting in RPython yet | 16:25 |
prologic | sadly :) | 16:25 |
jer | tbh i think that's one area io could be better at interpreting the error | 16:25 |
prologic | but it's coming along | 16:25 |
jer | if we encounter a ; or newline, and there are unbalanced ()'s []'s or {}'s, then throw an error | 16:25 |
jer | so long as the last token before the ; or ( was not a comma | 16:26 |
jer | so it'd still allow: | 16:26 |
jer | foo := method(a, b, | 16:26 |
jer | ... | 16:26 |
jer | ) | 16:26 |
jer | but not: 1 + 2 * (1 + 3 | 16:26 |
jer | oh and another corner case: comma or ( | 16:26 |
jer | foo := method( | 16:26 |
jer | ... | 16:26 |
jer | ) | 16:26 |
jer | should be legit too | 16:26 |
jer | this would give you PRECISE information about the line of the problem | 16:27 |
prologic | sure | 16:27 |
prologic | speaking of syntax | 16:28 |
prologic | would there be some syntax that would make sense for passing unevaluated message blocks around? | 16:28 |
prologic | reducing the need to inspect call message args | 16:28 |
jer | message(1 + 2) | 16:28 |
prologic | ahh perfect :) | 16:28 |
jer | oh | 16:28 |
jer | message(1 + 2) just creates a Message object | 16:29 |
prologic | or how about | 16:29 |
prologic | |1 + 2| | 16:29 |
prologic | as syntactic sugar | 16:29 |
prologic | where | 16:29 |
jer | i.e., message := method(Message clone fromString(call message arguments at(0) asString)) | 16:29 |
prologic | || = Message getSlot("message") | 16:29 |
jer | i don't like | 16:29 |
jer | you could define method() as syntax i guess | 16:29 |
jer | instead of itself a method | 16:30 |
jer | and then in its arg list | 16:30 |
jer | do something like: | 16:30 |
jer | method(a, b, c=unevaluated, ...) | 16:30 |
jer | the method would encode the position of c as an index into the arguments list | 16:30 |
jer | thus avoiding some boilerplate in your method body | 16:30 |
*** gatesphere has quit IRC | 16:30 | |
jer | c would be a message type inside your method | 16:30 |
prologic | *nods* | 16:30 |
jer | i don't like that either, but if i had to pick between || and that, i'd pick that | 16:31 |
jer | i want to implement an untyped term rewriting engine | 16:39 |
jer | i could most certainly use that to implement decent pattern matching for objc | 16:41 |
jer | in a library | 16:41 |
*** gatesphere has joined #io | 18:37 | |
*** fredreichbier has quit IRC | 19:25 | |
*** fredreichbier has joined #io | 23:26 |
Generated by irclog2html.py 2.11.0 by Marius Gedminas - find it at mg.pov.lt!