Advertisement

Scripting Language Genesis

Started by November 01, 2004 07:28 AM
116 comments, last by cmp 20 years, 2 months ago
Quote:
Original post by cmp
i think if you would have multiple parents, you would have to use sub children, as ever attribute may only occur once, at least as far as i know.

When I was writing that, I was just about to put interfaces and packages - but then I did remember that you can only have single attributes. But it will be good for if, for and while statements, and it could be possible to have source_file=... and source_line=... attributes, which would be quite cool.
Quote:
Quote:
Maybe I should make the parser using a state machine, and run it off a bnf. But that sounds like too much work to me.

i also thought about this, at least it would sound very cool to be independtent from external tools.
but the first thing is, that i will write my own xml like langauge, since it is really a pain to write everthing in xml and i only use a small subset of xml (tags, attribute).
i thout something like this:
*** Source Snippet Removed ***
i tried to write a simple converter yesterday, but had some bug, but it should just be 100 lines of code and would save from a lot of writing.

I'm going to write a design document first - with all the features that voodoo will have, and examples of the syntax. Then I think I will work on the virtual machine, doing the parser last.

I don't think xml is an acceptable format for bytecode - I think I will have to go with a binary file.

An idea that I had was that the constants in my language get exported to an xml file, and they can be overridden by other files. This way there will be less compilation.

To add extra features to the engine, you will have to compile the part of the engine that has the extra features (C++)
To add extra game logic you will have to compile the script with the new logic (voodoo)
To tweak the ingame constants you will have to edit an xml file (easy)

Also I think the file can store any constant - it won't be an error if the actual constant doesn't exist, it will be a sort of database. Constants will also be editable ingame, using a console type thing. I was also thinging about having an ingame script editor, so you don't even have to leave the game to create new functionality.

Also triggers can be setup in the console (like binding in the quake engine).

There will be two types of triggers, ones that need to be checked all the time, and others that can be called by code (key presses, events). This way the overhead for the trigger system can be lessened.

Update:

I no longer have access to "always on" internet, now on dialup. I will still be able to check this thread - it will just have to be once a day only.

[Edited by - umbrae on November 13, 2004 1:39:54 AM]
Quote:
I no longer have access to "always on" internet, now on dialup. I will still be able to check this thread - it will just have to be once a day only.

i don't know if this is the proper term, but i have pity on you.

Quote:
I don't think xml is an acceptable format for bytecode - I think I will have to go with a binary file.

i also thought about, this, but i think there is a binary xml work group @ w3c, but even if the don't releas sth. i just came up with my own format.
what i really like about the idea, is that you don't have any loss of information, wich fits the open source idea very nicely.
Advertisement
Quote:
Original post by cmp
i don't know if this is the proper term, but i have pity on you.


Pity is the right word. It is sad. I've got so used to fast internet. We had a wireless router which makes the change even worse, internet was available anywhere in the flat - without a cable. Now that Uni is over for the year, and we are between flats - I am back home with the 56k. Might see if I can persuade the family to get fast internet.

Quote:
Quote:
I don't think xml is an acceptable format for bytecode - I think I will have to go with a binary file.

i also thought about, this, but i think there is a binary xml work group @ w3c, but even if the don't releas sth. i just came up with my own format.
what i really like about the idea, is that you don't have any loss of information, wich fits the open source idea very nicely.


I suppose I could have a binary / xml hybrid, but I think that may be bad - text editors wouldn't really like it.

If I had two files that were produced, one that is completely binary and another that is xml, the xml gets parsed first and it says where in the binary file is the implementation for the particular methods. The xml file could also hold the linking information.

Edit:

I've started writing up the features of voodoo, what it is going to look like, the syntax, the built-in types etc. It's not quite finished yet, but at least it's a start.
i've looked at your design document, and i have a little suggestion, why not allow the user to set the step width of your ranges:
1..5,1 means [1,2,3,4,5], where 1..5,2 means [1, 3, 5]
i also think inclusive and exclusive isn't necassray, since your language don't uses infinte precission, 1...5 could be expressed as 1..4. (btw: wouldn't 1...5 at least in maths mean [2,3,4])

and do ranges return lists? if so you could even consider to rip them out of your language, since you could just supply a helper method like seq(begin, end, step). just my 2 cents.
Quote:
Original post by cmp
i've looked at your design document, and i have a little suggestion, why not allow the user to set the step width of your ranges:
1..5,1 means [1,2,3,4,5], where 1..5,2 means [1, 3, 5]
i also think inclusive and exclusive isn't necassray, since your language don't uses infinte precission, 1...5 could be expressed as 1..4. (btw: wouldn't 1...5 at least in maths mean [2,3,4])

Good idea. I mostly copied from the groovy ranges, I was wondering about the usefulness of the different types. I think I will just use 1..5 == [1, 2, 3, 4, 5].

Good idea for step, I did think about it. Just when was the last time you did a loop and had a step quantity that wasn't 1? I personally haven't for some time now (5 years?) But it could be an addition - as long as the default value was 1, so you could still say 1..5.

Quote:
and do ranges return lists? if so you could even consider to rip them out of your language, since you could just supply a helper method like seq(begin, end, step). just my 2 cents.

Your, and everone else's 2 cents are welcome. :)

It would be possible to have voodoo have no constant helper syntax, every new constant and string created as an object - but the syntax is there for ease of use. It is easier to say "1" than "integer.alloc().autorelease().init(1)", the same way that it is easier to say "for (integer i = 1..5)" compared to "for (integer i = 1; i < 5; i++)". I think that keeping ranges means that the language is easier to look at, and easier to write.

I think that there is a point when you have to say, just how far should we take this minimalistic approach? Yes minimal and object oritented is good, but there has to be a point when it goes too far. For example it would be possible to completely remove operators, just have methods. But this is bad, and operators are good.

It is about balance, and I think that having convenience methods for constant construction is a good thing. It's always going to be possible to create ranges the normal way - and yes they are a specialisation of lists.

Also with ranges it will be possible to do this:
1..5.each    system.print(value)


I'm working on a syntax similar to methods that will allow user creation of closures - I will post it when I have a little more time to work it out.
Quote:

Good idea for step, I did think about it. Just when was the last time you did a loop and had a step quantity that wasn't 1? I personally haven't for some time now (5 years?) But it could be an addition - as long as the default value was 1, so you could still say 1..5.

i just came up with the step idea, because my caluclator for maths course (it's the advanced one) can handle lists, and there you can say sth. like seq(x, x, 1, 5, 1) * 2, wich then returns a list with [2, 4, 6, 8, 10], and sometimes it's just nice, if you are able to set the step width and don't have to think about the right factor to scale the result list.

another little idea, for your lists i would implement inner and outer operators (at leas it's called this way in vector maths), where each inner operator means the list linked with any object of the element type, then the operation is performed on every single element, and an outer operation where the list is linked with another list.
for the outer operation it's hard to define one rule for the operator function, since it would for example nice to have a concat operator, but also a per element addition:
[1,2,3] . [4,5,6] gives [1,2,3,4,5,6], when "." is the concat operator
[1,2,3] + [4,5,6], gives [5,7,9].
[1,2,3] * 5 gives [5,10,15]

these operators would just ease working with your lists, if you really want to implement everthing yousefull, you should also consider subtraction and intersection of lists.
Advertisement
Quote:
Original post by cmp
another little idea
...
these operators would just ease working with your lists, if you really want to implement everthing yousefull, you should also consider subtraction and intersection of lists.

I am planning to implement those methods (.intersect() .union() etc.) it's just a matter of choosing appropriate operators. Also there will be a range of init methods that help in the creation of lists. eg.
integer[] i = list.seq(parameters)
and I think that operators could be transparent to the list, for example if the * operator between two integers was multiplication, then [1, 2, 3] * 2 would equal [2, 4, 6]. The operator would automatically be called on each element in the list - even for user defined operators between custom classes.

Just my first idea for closure syntax... the each method in a list...
class list    // normal method    - boolean equals(list l)        return value == l.value    // closure    - void each{object o}        for i = 0..size            each(self)


The actual code is quite contrived but illustrates the point. This now means that you can do something like:
list l = [1, 2, 3]l.each    system.print(o)


Not sure if the actual call should be the name of the closure (each) or a generic keyword like closure (similar to the keyword self).
// closure- void each{object o}    for i = 0..size        each(self)

or
// closure- void each{object o}    for i = 0..size        closure(self)


Actually having written this I realise that there are two return types, the one that the code in the closure returns - and the one that the closure itself returns. eg
list new_list = other_list.map    return x * x

This takes one list and returns the list with each value squared. The closure itself returns a list, the code in the closure returns an integer (or whatever type x is).

Back to the drawing board.
could you explain what closures really are?
currently i do not understanding them, and i'm to lazy to read it in the groovy doc - i actually tried once, but i stopped, because i didn't understand much.

update: i've released the micro xml to xml converter.
micro xml is my xml derivat, wich should be much faster to type, since you do not need to put closing tags.
you can get it here - look under files.

[Edited by - cmp on November 15, 2004 12:16:38 PM]
for your 1...5 argument, I would recommend you do math notation.

(1...5,1] would be 2, 3, 4, and 5.
(1...5,2) would be 3
[1...5,2] would be 1, 3, 5

Get my drift? That would be sweet.
Quote:
Original post by umbrae
Just my first idea for closure syntax... the each method in a list...
class list    // normal method    - boolean equals(list l)        return value == l.value    // closure    - void each{object o}        for i = 0..size            each(self)


Erm. That's not a closure. That's a function that accepts a function as a (hidden) argument.



I'd do
class list  equals (list l)    for i = 0 .. size      if  != l.        return false    return false  each (f)    for i = 0 .. size      f()

And have special magic that says that a block following a function call is passed as the function's last argument.
Quote:

Actually having written this I realise that there are two return types, the one that the code in the closure returns - and the one that the closure itself returns. ... The closure itself returns a list, the code in the closure returns an integer (or whatever type x is).

If you must have explicit typing:
class list<T>  boolean equals (list<?> l)    for int i = 0 .. size      if  != l.        return false    return false  void each ((T -> ?) f)    for int i = 0 .. size      f()list<int> l = [1, 2, 3]list.each ((i:int -> int) i ** 2)
CoV

This topic is closed to new replies.

Advertisement