UnitedLexCorp / SimpleTalk

An implementation of HyperTalk in Ohm-js
Apache License 2.0
7 stars 1 forks source link

[wip] Calculator #208

Open ApproximateIdentity opened 3 years ago

ApproximateIdentity commented 3 years ago

I'm trying to program a basic calculator. And figured I'd just open a PR. Pull this down and open the calculator.html file in the examples folder.

The current state is that there are buttons for each of the numbers and for plus, multiplies and equals. They do no logic though. They just set a field to the value of the button that is clicked. So I have two main questions:

  1. What's the best way to "update" a field? Do we have an "append" command for strings? This would allow at least producing a string like "1343+313" in the field using the buttons.
  2. What's the best way to evaluate that string? I don't mean something fancy and smart and better at handling errors (evaluating whatever string that comes in is maybe a little crazy), but say how do I turn "20+3" into "23" when I press the equals button?

I think given that it'll already be functional enough as a first little version. There are probably better ways to store the state, but I'm not too worried about that atm.

dkrasner commented 3 years ago

@ApproximateIdentity

I'm trying to program a basic calculator. And figured I'd just open a PR. Pull this down and open the calculator.html file in the examples folder.

The current state is that there are buttons for each of the numbers and for plus, multiplies and equals. They do no logic though. They just set a field to the value of the button that is clicked. So I have two main questions:

1. What's the best way to "update" a field? Do we have an "append" command for strings? This would allow at least producing a string like "1343+313" in the field using the buttons.

we have string concat (append is of course a special case of concat):

answer "AAA" & "BBB"

will produce what you expect.

So you can do [some command] the "text" [objectSpec?] & "[New String]"

for example, in a field run

answer the "text" & "AAA"

which will do exactly the right thing, producing 'answer the "text" & "AAA"AAA`

so you can updated the text prop of a field using this and related.

2. What's the best way to evaluate that string? I don't mean something fancy and smart and better at handling errors (evaluating whatever string that comes in is maybe a little crazy), but say how do I turn "20+3" into "23" when I press the equals button?

we don't have string eval, so i am not sure how you would go about doing this, but I don't think it should be with evaluating string representations of ST expressions.

Here is an example:

answer "2" + "2"
answer "2" & "2"

produce the same output "22," which I think is incorrect. We should allow "+," and related operators, to coerce their arguments, i.e. "2" + "2" will first call the Number on the arguments to "+" in the interpreter. This might have been the original plan and was just overlooked, so technically a bug.

This way you can store args to your calculator, or whatever in a field and then evaluate them as they come in

I think given that it'll already be functional enough as a first little version. There are probably better ways to store the state, but I'm not too worried about that atm.

ApproximateIdentity commented 3 years ago

Cool thanks that makes a lot of sense. And yeah I agree it seems better not to have a full eval going. I'll play around with this.

dkrasner commented 3 years ago

np. let me know if you want to hack at the interpreter together (I was happy to do so with eric the first time around)

this might also be a good time to flush out our core arithmetic and math library which is rather limited, above issue aside, at the moment

i would say we at least want arithmetic, trig, logs, more less what is here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math

ApproximateIdentity commented 3 years ago

@darth-cheney @dkrasner Okay I have a complete initial version of four-function calculator.

To use this you must first press clear (i.e. the "C") button. (It's stupid, but I wasn't sure how to get around it to initialize things.)

After that you can add, subtract, multiply and divide. This version does not currently allow "continued" evaluation (i.e. pressing equals and then continuing on with the result). It also does not allow multiple operators (e.g. 4+3+4 does not work only 4+5). At any point you can press "C" i.e. clear to reset the state.

So ignoring that I don't have the more complex extensions going (i.e. continually evaluating with previous results), what I mainly wonder is what you think about the way I coded it. The code is super simple so if you load up the examples/calculator.html and look at the buttons code, you'll understand immediately what's going on. Is there anything here that I'm doing especially stupid?

dkrasner commented 3 years ago

we prob want the example to be able to do what a regular calculator can, which includes continual operations

darth-cheney commented 3 years ago

@ApproximateIdentity In addition to @dkrasner 's comments, I think you can handle your initialization by scripting an openCard handler on the card itself (or even openStack on the stack, if you prefer). That way you don't have to push the clear button to init the variables etc.

ApproximateIdentity commented 3 years ago

@darth-cheney What's the best way to do that? Is there some way to do that within the buttons themselves? Everything else about this is only in the buttons and can be added explicitly and visually. Can we do that for the card as well?

Another option is to check if the variables exist, and explicitly set them if not. But I wasn't totally sure how to do that.

darth-cheney commented 3 years ago

@ApproximateIdentity

What's the best way to do that?

You are going to need to open a script editor on the card or stack. I think the command to do that is openScriptEditor <partId>, so maybe openScriptEditor (the "id" of current card) might work? You could make a button that does this or alt+highlight to execute it inline in some Field.

Is there some way to do that within the buttons themselves? Everything else about this is only in the buttons and can be added explicitly and visually. Can we do that for the card as well?

I'm not exactly sure what you mean here, but if it's about whether or not other parts like the Buttons have similar lifecycle messages like openCard and openStack they don't at the moment. We could think about implementing something like that. Another related option might be some sort of afterPaste message that is sent to a Part after it has been pasted. That way you have a reusable component.

Another option is to check if the variables exist, and explicitly set them if not. But I wasn't totally sure how to do that.

One thing you could do is extend the grammar and semantics for the ThereIsAn conditional rule to also look up variable values (for the moment it only does ObjectSpecifiers).

What you are pointing out here is a real issue though: we want to be able to create components that are reasonably self contained and we should think about how to accomplish this. One thing I've been thinking about is the idea of custom user-specified properties on parts. These would be "basic" properties that users could give names and values to, and they would follow the parts around. That would also solve your problem, as you could just attach the properties to an enclosing Area for the whole calculator and that would be the end of it

ApproximateIdentity commented 3 years ago

@darth-cheney

I'm not exactly sure what you mean here...

What I meant was, is there a way for me to test if a variable has been set? I.e. my clear button sets the global variables to empty strings, but before I've pressed clear, they are not set at all so if I try to reference them I get errors. Is there currently a way for me to check if the global variables don't exist?

darth-cheney commented 3 years ago

@ApproximateIdentity

is there a way for me to test if a variable has been set?

At present there is not. But that's what I was suggesting at the end of my previous comment -- we might want to extend ThereIsAnObject rule to also take variables (right now it only takes ObjectSpecifiers). This would require updating both the grammar and the semantics. But in the end you would be able to do something like if there is a someVariable then doSomething

ApproximateIdentity commented 3 years ago

@ApproximateIdentity

is there a way for me to test if a variable has been set?

At present there is not. But that's what I was suggesting at the end of my previous comment -- we might want to extend ThereIsAnObject rule to also take variables (right now it only takes ObjectSpecifiers). This would require updating both the grammar and the semantics. But in the end you would be able to do something like if there is a someVariable then doSomething

Do you think that sort of thing makes sense to do now? My personal thought is that either that, or some sort of a constructor like thing should exist on an object. In this case the constructor only needs to live on the box presenting the output since every other button is stateless and only sends the same message at all times.