Jump to content

[WIP] Jebnix - A kOS Alternative


woodywood245

Recommended Posts

I suppose that's true. I may put it in anyway and let people decide whether or not they want to use it. The implementation of a DO... WHILE loop is almost identical to that of a WHILE loop, so it's something I could whip up and test in only a few minutes.

I've had a thought about FOR loops. It could be done similar to how it is done in Visual Basic:


for x from 0 to 5 step 1
{
}

for [control variable] from [start] to [end] [opt:step [count]]
{
}

Using the STEP keyword is optional. Without it, the value is stepped by 1 or -1, depending upon whether the end value is larger than the start.

Link to comment
Share on other sites

I am not sure what direction you want to take kOS, but looking at it from the point of wanting to develop a compact and easy language I might not bother with do... loops at all. People can substitute it with barely any code themselves.

On a second thought, I won't bother adding DO...WHILE. Not yet, anyway.

Link to comment
Share on other sites

If you're going to make a different version of the kosscript language from what's in erendrake's version, it's probably a good idea to pick a naming convention for the fork of the language you're making. Just so people writing scripts can say things like "this program is written in jebscript not kosscript" (or whatever ends up being the names).

Basically there's a long tradition of being able to divorce the naming of the language variant from the naming of one particular program that implements it, so that if you change a language a lot in your implementation it's a good idea to give it a different name so you don't have to refer to it as "the version of the language that that program does instead of the version that this program does."

Link to comment
Share on other sites

I suppose that's true. I may put it in anyway and let people decide whether or not they want to use it. The implementation of a DO... WHILE loop is almost identical to that of a WHILE loop, so it's something I could whip up and test in only a few minutes.

I've had a thought about FOR loops. It could be done similar to how it is done in Visual Basic:


for x from 0 to 5 step 1
{
}

for [control variable] from [start] to [end] [opt:step [count]]
{
}

What about using syntax similar to Python?


for x in range(0,5,1):

for [control variable] in range([start],[end],(opt:step [count]))

for x in list:

for [control variable] in [array]:

I have always found the syntax of Python to be one of the easiest to understand what a given command does.

Link to comment
Share on other sites

What about using syntax similar to Python?


for x in range(0,5,1):

for [control variable] in range([start],[end],(opt:step [count]))

for x in list:

for [control variable] in [array]:

I have always found the syntax of Python to be one of the easiest to understand what a given command does.

That's a really good idea. I might do that, thanks!

It will depend on how easy it is to code in relation to the VB-based idea, and whether it fits well within the existing syntax of the language. But I will look into it.

Edited by woodywood245
Link to comment
Share on other sites

If you're going to make a different version of the kosscript language from what's in erendrake's version, it's probably a good idea to pick a naming convention for the fork of the language you're making. Just so people writing scripts can say things like "this program is written in jebscript not kosscript" (or whatever ends up being the names).

Basically there's a long tradition of being able to divorce the naming of the language variant from the naming of one particular program that implements it, so that if you change a language a lot in your implementation it's a good idea to give it a different name so you don't have to refer to it as "the version of the language that that program does instead of the version that this program does."

I'm calling my version of the language KerboScript++.

Link to comment
Share on other sites

That's a really good idea. I might do that, thanks!

It will depend on how easy it is to code in relation to the VB-based idea, and whether it fits well within the existing syntax of the language. But I will look into it.

For maximum flexibility, I'd prefer something akin to the C for loop, which is so versatile you can use it for everything.

Here's the starting setup,

Here's the boolean check between iterations.

Here's the thing to increment each time.

Link to comment
Share on other sites

It could be done similar to how it is done in Visual Basic:


for x from 0 to 5 step 1
{
}

for [control variable] from [start] to [end] [opt:step [count]]
{
}

I like the Basic approach. It is nice and... basic.

Link to comment
Share on other sites

Given the opinions given, and the simplicity in syntax, I think I'm going to go with a Visual Basic-like for-loop. It will be much easier to parse that way.

This is far easier to parse with my setup than anything else:


for [expression] from [expression] to [expression] [opt:step [expression]] { }

Link to comment
Share on other sites

Given the opinions given, and the simplicity in syntax, I think I'm going to go with a Visual Basic-like for-loop. It will be much easier to parse that way.

This is far easier to parse with my setup than anything else:


for [expression] from [expression] to [expression] [opt:step [expression]] { }

But the important question is when do the expressions get evaluated? Up front before the first loop iteration (making them effectively a static constant once the loop is executing), or again and again each loop iteration (making the expression capable of containing live dynamic logic in it).

That's a difference that is more than just syntactic sugar. If a for loop must have a fixed number of iterations before it starts, that actually affects the sorts of algorithms a for loop can be used for.

Edited by Steven Mading
Link to comment
Share on other sites

But the important question is when do the expressions get evaluated? Up front before the first loop iteration (making them effectively a static constant once the loop is executing), or again and again each loop iteration (making the expression capable of containing live dynamic logic in it).

That's a difference that is more than just syntactic sugar. If a for loop must have a fixed number of iterations before it starts, that actually affects the sorts of algorithms a for loop can be used for.

If labeling the expressions A, B, C, and D respectively, then...


for A from B to C step D
{
// your code here
}

... is functionally identical to...


set A to B.
while A <= C
{
// your code here
set A to A + D.
}

"SET x TO y." requires that the expression x evaluate to a variable, whether it exists or not. The reason I say "expression" is because "a[b+c]" is a valid expression, representing a location in an array. Expression y must simply evaluate fully. Therefore, A must evaluate to a variable, while B, C, and D must simply fully evaluate to a value of some kind.

Setting A to B is run only once, before the loop begins. Then, expression A <= B is evaluated. If it evaluates as TRUE, the loop executes. At the end of the loop, A is incremented/decremented according to D, if it exists. Otherwise, D is set to 1, the sign is inferred from B and C (via D = A - B >= 0 ? 1 : -1) and the increment/decrements happens accordingly. Then the loop starts back at the beginning, evaluating A >= C.

I hope that makes sense and answers your question.

Link to comment
Share on other sites

If labeling the expressions A, B, C, and D respectively, then...


for A from B to C step D
{
// your code here
}

... is functionally identical to...


set A to B.
while A <= C
{
// your code here
set A to A + D.
}

"SET x TO y." requires that the expression x evaluate to a variable, whether it exists or not. The reason I say "expression" is because "a[b+c]" is a valid expression, representing a location in an array. Expression y must simply evaluate fully. Therefore, A must evaluate to a variable, while B, C, and D must simply fully evaluate to a value of some kind.

Setting A to B is run only once, before the loop begins. Then, expression A <= B is evaluated. If it evaluates as TRUE, the loop executes. At the end of the loop, A is incremented/decremented according to D, if it exists. Otherwise, D is set to 1, the sign is inferred from B and C (via D = A - B >= 0 ? 1 : -1) and the increment/decrements happens accordingly. Then the loop starts back at the beginning, evaluating A >= C.

I hope that makes sense and answers your question.

Not really. It doesn't clarify what this does:


set endp to 5.
set incr to 1.
FOR A from 1 to endp STEP incr {
print "A is now " + A.
set endp to 40.
set incr to A.
}.

If the expressions in the for syntax evaluate up front once, then it does this:

A is now 1

A is now 2

A is now 3

A is now 4

A is now 5

If they evaluate each time dynamically, then it does this:

A is now 1

A is now 2

A is now 4

A is now 8

A is now 16

A is now 32

Does changing the value of endp or incr inside the loop body do anything to the checks, or have those expressions already been evaluated into a final answer by then and only the final answer is remembered?

That was my question.

Another example of where the two approaches differ is what happens when you insert or delete from the very list that you are iterating over.

If you use a for loop to iterate from 1 to list:length, and the purpose of the loop is to insert some items into the list whenever an item is found that fits certain criteria, then when does the loop stop? If list:length was originally 10, but your loop added 2 items to the list as it goes, does it stop at the original value of 10 or does it re-evaluate the expression list:length each time so it stops at 12?

That's the meat of my question.

Link to comment
Share on other sites

Not really. It doesn't clarify what this does:


set endp to 5.
set incr to 1.
FOR A from 1 to endp STEP incr {
print "A is now " + A.
set endp to 40.
set incr to A.
}.

If the expressions in the for syntax evaluate up front once, then it does this:

A is now 1

A is now 2

A is now 3

A is now 4

A is now 5

If they evaluate each time dynamically, then it does this:

A is now 1

A is now 2

A is now 4

A is now 8

A is now 16

A is now 32

Does changing the value of endp or incr inside the loop body do anything to the checks, or have those expressions already been evaluated into a final answer by then and only the final answer is remembered?

That was my question.

Another example of where the two approaches differ is what happens when you insert or delete from the very list that you are iterating over.

If you use a for loop to iterate from 1 to list:length, and the purpose of the loop is to insert some items into the list whenever an item is found that fits certain criteria, then when does the loop stop? If list:length was originally 10, but your loop added 2 items to the list as it goes, does it stop at the original value of 10 or does it re-evaluate the expression list:length each time so it stops at 12?

That's the meat of my question.

Given the code:


set endp to 5.
set incr to 1.
FOR A from 1 to endp STEP incr {
print "A is now " + A.
set endp to 40.
set incr to A.
}.

Your output would be:


A is now 1.
A is now 2.
A is now 4.
A is now 8.
A is now 16.
A is now 32.

A, endp, and incr are stored as variables just like any other variable. Each time through the loop, they are evaluated for that one time. The values that are provided at the beginning of the loop only matter for the first time through. They are not remembered, and the expressions are evaluated every time through.

Therefore, if you start looping through an array of 10 elements, and add 10 more elements onto the end, but tell it not to stop until the end of the array is reached, then you will stop after 20 elements.

Link to comment
Share on other sites

So, is the "+" being looked at in a numerical operand case or as a string modifier, or 'both'???

The + operator is playing three rolls: as the addition operator, the string concatenation operator, and the unary "positive" operator. Which it uses is determined by context. Most of the operators use a set of rules, where, in the case of A ~ B, where A and B are operands, and ~ is an operator, if A or B is a string, do one thing. If A or B is an integer, do something else. If A or B is a double, do a third thing. In any other case (like A and B are both strings), cast them to some predefined type and perform the correct operation:

Example: the binary + operator

If A is a string, or B is a string, convert A and B to strings and concatenate. Return a string.

Otherwise...

If A is a double, or B is a double, convert A and B to doubles and add. Return a double.

Otherwise...

If A is an integer, or B is an integer, convert A and B to integers and add. Return an integer.

Otherwise...

If A is a boolean, or B is a boolean, convert A and B to integers, add them, and convert back to a boolean (non-zero is true, zero is false)

Otherwise...

If A is an ordered pair, or B is an ordered pair, convert A and B to ordered pairs and perform a element-wise addition. Return an ordered pair.

Example: the binary - operator

If A is a double, or B is a double, convert A and B to doubles and subtract the B from the A. Return a double.

Otherwise...

If A is an integer, or B is an integer, convert A and B to integers and subtract the B from the A. Return an integer.

Otherwise...

If A is a boolean, or B is a boolean, convert A and B to integers, subtract B from A, and convert back to a boolean (non-zero is true, zero is false)

Otherwise...

If A is an ordered pair, or B is an ordered pair, convert A and B to ordered pairs and perform an element-wise subtraction. Return an ordered pair.

Otherwise...

Convert A and B to doubles, regardless of type, and subtract B from A. Return a double.

Source code for these operations can be found here (this link takes you to the file and line number where operator overloads begin): https://github.com/griderd/Jebnix/blob/master/Jebnix/Types/Value.cs#L279

That's why there's a difference between

print "2+2=" + (2 + 2).

and

print "2+2=" + 2 + 2.

Operations are performed using order of operations, and left to right, just like most ordinary math. The first code results in "2+2=4", while the second results in "2+2=22". The first expression has the evaulator perform the operation in the parentheses first (integer addition), then the operation outside (string concatenation). The second expression has the evaluator perform the operations left to right, starting with a string concatenation, which results in a string, followed by another.

Edited by woodywood245
Link to comment
Share on other sites

A, endp, and incr are stored as variables just like any other variable.

Yes, I knew that. But THIS:

and the expressions are evaluated every time through.

Is what hadn't been specified until now. It's basically the difference between whether is is SETting the end condition to the expression or LOCKing the end condition to the expression. Now it's clear.

Although it does bring up another question: does it check the sign of the increment again each time too? If someone did something utterly ridiculous and say started a loop going from A to B step C, in which A < B, and then partway through changed B to a small number such that A > B, would the loop know to reverse the direction of the increment C? Or is the direction of the increment only determined once up front and then it stays that way? You basically said that the programmer doesn't need to specify the sign of C because the system automatically chooses whether to add or subtract C based on whether A <B or A > B. But is that decision re-evaluated each time as well as the expression C being re-evaluated?

Link to comment
Share on other sites

It never changes the expressions it's provided, and if no increment value is provided via STEP, the increment value is statically determined only once ahead of the loop, and then set as a constant literal.

I'll put it this way: Jebnix stores the expression tokens it needs and pushes them as metadata onto the call stack at the top of the loop. Whenever the end of the loop is reached, the expressions are popped off the call stack, and evaluated to determine whether to continue the loop. The expressions never change from the original ones they're given, and the variables only change according to what they are told to do.

Loops in Jebnix will operate EXACTLY the same as loops in C/C++/Java/C#/Visual Basic, and pretty much any other language you would come across.

Link to comment
Share on other sites

Loops in Jebnix will operate EXACTLY the same as loops in C/C++/Java/C#/Visual Basic, and pretty much any other language you would come across.

Given what you said here that is false.

But at any rate it seems like it will be easy to work with and I can always resort to a more raw approach using an "until" loop when I want to make the sorts of for loops that this structure doesn't support.

Link to comment
Share on other sites

Given what you said here that is false.

But at any rate it seems like it will be easy to work with and I can always resort to a more raw approach using an "until" loop when I want to make the sorts of for loops that this structure doesn't support.

The definition of a for loop, according to cppreference.com: "Executes init-statement once, then executes statement and iteration_expression repeatedly, until the value of condition becomes false. The test takes place before each iteration."

C/C++ Syntax:

for ([I]init-statement[/I]; [I]condition[/I]; [I]iteration_expression[/I]) [I]statement[/I]

Which is equivalent to:


[I]init_statement[/I];
while ([I]condition[/I]) {
[I]statement[/I]
[I]iteration_expression[/I];
}

In Visual Basic.Net, according to MSDN:


For counter [ As datatype ] = start To end [ Step step ]
[ statements ]
[ Continue For ]
[ statements ]
[ Exit For ]
[ statements ]
Next [ counter ]

Technical Implementation

When a For...Next loop starts, Visual Basic evaluates start, end, and step. Visual Basic evaluates these values only at this time and then assigns start to counter. Before the statement block runs, Visual Basic compares counter to end. If counter is already larger than the end value (or smaller if step is negative), the For loop ends and control passes to the statement that follows the Next statement. Otherwise, the statement block runs.

Each time Visual Basic encounters the Next statement, it increments counter by step and returns to the For statement. Again it compares counter to end, and again it either runs the block or exits the loop, depending on the result. This process continues until counter passes end or an Exit For statement is encountered.

The loop doesn't stop until counter has passed end. If counter is equal to end, the loop continues. The comparison that determines whether to run the block is counter <= end if step is positive and counter >= end if step is negative.

If you change the value of counter while inside a loop, your code might be more difficult to read and debug. Changing the value of start, end, or step doesn't affect the iteration values that were determined when the loop was first entered.

Step Argument

The value of step can be either positive or negative. This parameter determines loop processing according to the following table:

[table=width: 500, class: grid]

[tr]

[td]Step value[/td]

[td]Loop executes if[/td]

[/tr]

[tr]

[td]Positive or zero[/td]

[td]counter <= end[/td]

[/tr]

[tr]

[td]Negative[/td]

[td]counter >= end[/td]

[/tr]

[/table]

The default value of step is 1.

In KerboScript++:

If labeling the expressions A, B, C, and D respectively, then...


for A from B to C step D
{
// your code here
}

... is functionally identical to...


[B]set[/B] A to B.
while A <= C
{
// your code here
set A to A + D.
}

"SET x TO y." requires that the expression x evaluate to a variable, whether it exists or not. The reason I say "expression" is because "a[b+c]" is a valid expression, representing a location in an array. Expression y must simply evaluate fully. Therefore, A must evaluate to a variable, while B, C, and D must simply fully evaluate to a value of some kind.

Setting A to B is run only once, before the loop begins. Then, expression A <= B is evaluated. If it evaluates as TRUE, the loop executes. At the end of the loop, A is incremented/decremented according to D, if it exists. Otherwise, D is set to 1, the sign is inferred from B and C (via D = A - B >= 0 ? 1 : -1) and the increment/decrements happens accordingly. Then the loop starts back at the beginning, evaluating A >= C.

If the value of D is not given, it is assigned once, ahead of the loop executing, based upon the values of B and C. By default it is set to 1, or -1. The ternary expression I gave is actually wrong, I meant it as

D = C - B >= 0 ? 1 : -1


for x from 1 to 5 { }
for y from 5 to 1 { }

Is equivalent to:


for x from 1 to 5 step 1 { }
for y from 5 to 1 step -1 { }

Is equivalent to:


set x to 1.
while x < 5
{
set x to x + 1.
}

set y to 5.
while y > 5
{
set y to y + -1.
}

While these....


set a to 5.
for x = 1 to a step 1
{
if x > 3
{
set x to 10. // loop ends after this line
}
}

// this is an infinite loop
for x = 1 to a step 1
{
if x > 3 { set x to -5. }
}

for x = 0 to a step 3
{
if x > 2 { set a to 10. }
print x.
}
// this loop prints:
// 0
// 3
// 6
// 9

Are equivalent to, in C/C++:


int x, a = 5;
for (x = 1; x < a; x++)
{
if (x > 3)
x = 10;
}

for (x = 1; x < a; x++)
{
if (x > 3)
x = -5;
}

for (x = 0; x < a; x+=3)
{
if (x > 2)
a = 10;
printf("%i\n", x);
}

Link to comment
Share on other sites

Continuing on the discussion of how loops will be implimented, will there be a break statement? I see there is a return function mentioned, but no break function mentioned in the first post.

Link to comment
Share on other sites

Continuing on the discussion of how loops will be implimented, will there be a break statement? I see there is a return function mentioned, but no break function mentioned in the first post.

The break statement as well as the continue statement will be implemented.

Link to comment
Share on other sites

I assumed the cases where the C approach to for loops do a thing the visual basic approach does not were obvious and I didn't want to spend a whole post outlining them, but since they apparently weren't, I'll have to do that now.

In your proposed system, the loop MUST have exactly one counter variable, no more and no less. It MUST be a number or at least an object like an iterator for which the operators +, -, <=, and >= are implemented. In a C++ for loop the initializer can be any statement you feel like and can even be omitted. If you'd like to design a loop that tracks using a pointer, you can. If you'd like to use a loop that tracks using a reference, you can.

In your proposed system, the ending condition MUST be of the form A <= expr or A >= expr, where A is the counter variable. In the C++ approach you can use any particular boolean expression you feel like, and it can contain any combination of ands and ors, and it doesn't have to be a numerical check where "<=" and ">=" make sense. You could, for example, test for whether or not nextNode == NULL when traversing a list or tree.'

In your proposed system, the incrementer must be of the form A = A + C, or A = A - C, where A is the loop counter and C is the step. Any other type of increment is not supported. You can't walk a tree for example by having an incrementer that says A = A.getNextNode().

Here's a simple example of a thing that I don't think your proposed for loop supports that C, C++, and Java do support:


// Binary search on an already sorted array of strings for the index of the hit, or return -1 if no hit found:
// assume the following variables exist before starting:
// char needle[] = "some string I'm looking for";
// char *haystack[] is a sorted array of the strings being searched
// int haystackSize is the length of the haystack array.
// int min, max. middle, cmp;
for( min=0, max=haystackSize ;
min <= max || cmp != 0 ;
(cmp<0 ? max = min + middle : min = min + middle) )
{
middle = ((max-min)+1) / 2;
cmp = strcmp( needle, haystack[middle] );
}
if( cmp == 0 ) {
// hit was found at index "middle".
} else {
// hit was not found.
}

Note: I haven't compiled and tested that. It's written from memory about how the basic algorithm works and it could include things like off-by-one errors and such. My goal was not to write perfectly debugged code but to show an example of how the for loop is truly open-ended and unrestricted in C/C++/Java much more so than what you're proposing, precisely because it does *less* built-in logic and therefore doesn't dictate anything about how the loop is required to work.

Arguments have been made that this is a bad feature of those languages and it makes the FOR loop confusing. I'm not trying to enter that argument. I don't agree with it, but I also don't care as much about it. What I do care about is that you made the claim that you can do all the same things with the FOR loop you're proposing that can be done in C/C++/Java and that this claim shows a large misunderstanding of how the FOR loop works in those languages. In those languages, the FOR loop is nothing more than a way of re-writing a WHILE loop with some of the code moved from the body to the header, and as such it doesn't dictate anything about the actual algorithm.

Which is why I said that that I could cover the cases that your for loop doesn't cover, but C/C++/Java for loops do cover, by using an UNTIL instead. an UNTIL is just a WHILE with an implied "not" applied to the boolean check.

If you were going with the sort of FOR loop that exist in C/C++/Java, than ANY code of the following format:


stuffAAA.
UNTIL stuffBBB {
stuffCCC.
stuffDDD.
}

Could be re-written as:


for( stuffAAA ; not( stuffBBB ) ; stuffDDD ) {
stuffCCC.
}

For any arbitrary stuffAAA, stuffBBB, stuffCCC, and stuffDDD. Regardless of whether that stuff includes counting a variable up or down across a range of numbers.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...