How to use and extend BiwaScheme

BiwaScheme is scheme implementation in Javascript.

Here you can find scheme interpeter using BiwaScheme (using JQuery Terminal Emulator inside JQuery UI Dialog). If you want to download BiwaScheme package click here.

BiwaScheme use prototype javascript library.

If you wat to use interpreter in your own code you must:

  • add this to head tag
    http://src/development_loader.js

    or if you want to make distribution you must have make and YUI Compressor which require java

    Uncomress package and type make in biwascheme directory it will create lib/biwascheme.js file which is compressed library. You must put it in head of your html file:

    lib/biwascheme.js
  • Create instance of Interpreter class
    var intepreter = new BiwaScheme.Interpreter();
  • You can also put function for error handling to the constructor
    var biwascheme = new BiwaScheme.Interpreter(function(e, state) {
        $('output')[0].innerHTML += e.message;
    });
    
  • If you want to result be proper displayed you must overwrite puts function
    var output = $('ouptut');
    function puts(str, no_newline) {
        if (no_newline) {
            output[0].innerHTML += str;
        } else {
            output[0].innerHTML += str + "<br />";
        }
    }
    
  • Evaluating funtion should look like this:
    var input = $('input');
    var output = $('output');
    function scheme_eval(e) {
        try {
            var code = input.html();
            // show trace messages
            if (trace) {
                var opc = interpreter.compile(code);
                var dump_opc = (new BiwaScheme.Dumper()).dump_opc(opc);
                output[0].innerHTML += dump_opc;
            }
            interpreter.evaluate(code, function(result) {
                if (result != undefined) {
                    result = BiwaScheme.to_write(result);
                    output[0].innerHTML += '> ' + result + "\n";
                }
            });
        } catch(e) {
             //this will never be evaluated because all errors are
             //pased to function pased to Interpreter constructor
             output[0].innerHTML += e.message;
             throw(e);
        }
    }
    
  • You could bind this function with onclick event
    $('eval_btn').click(scheme_eval);
  • If you want to define new function which will be accessable in your scheme interpreter you should use define_libfunc function from global object BiwaScheme. First parametr is scheme name of the function, second and third are minimum and maximum of parameters and fourth is the anonimus function with one argument which is array of parameters pased to scheme procedure.
    BiwaScheme.define_libfunc('env', 0, 0, function(args) {
            var result = new Array();
            for(fun in window.BiwaScheme.CoreEnv) {
                result[result.length] = fun;
            }
            // result should be converted from array to scheme list
            return result.to_list();
        });
    

    This function will return list of all function and variables in scheme global Environment.

    The following scheme function will display that list:

    (define (show-env)
      (let iter ((list (env)))
        (if (not  (null? list))
            (begin
               (display (car list))
               (newline)
               (iter (cdr list))))))

    or simplier.

    (define (show-env)
      (display (string-join (env) "\n"))
      (newline))
    
  • If you want to define some variable you must put it in BiwaScheme.CoreEnv array.

    If you want to define (in javascript) function with scheme code use BiwaScheme.define_scmfunc. First parameter is scheme name, second and third are minimum and maximum of parameters (BiwaScheme check this before function are evaluated) and the fourth one is string containing your scheme code (should be lambda expresion).

    BiwaScheme.define_scmfunc('**', 1, 1,
            "(lambda (x y) \
                 (cond \
                     ((= y 0) 1) \
                     ((< y 0) (** (/ 1. x) (- y))) \
                     (else \
                        (let iter ((i 1) (result x)) \
                           (if (= i y) \
                               result \
                               (iter (+ i 1) (* result x)))))))");

    Former function define power with tail recursion.

    You could also create scheme macro in javascript with BiwaScheme.define_syntax function. This function must return BiwaScheme.Pair object which will be evaluated. It accept single parameter which is scheme expression (tree build from BiwaScheme.Pair objects). This is example of using macros from javascript:

    //this is helper Array method which traverse a tree build with arrays 
    //and create tree of Symbols
    // it use to_list function wich is defined by BiwaScheme
    Array.prototype.to_tree = function() {
        for(var i in this) {
            if (this[i] instanceof Array) {
                return this[i].to_tree();
            }
        }
        return this.to_list();
    };
    
    BiwaScheme.define_syntax('foo', function(expr) {
        return [BiwaScheme.Sym("display"),
                [BiwaScheme.Sym("quote"), expr.cdr.to_array().to_tree()]
               ].to_tree();
    });
    

    This code create new macro foo which simply display expression passed as parameters. Note that the whole expression is in expr.cdr filed.

  • In interpeter you could also define macros (like common lisp macros) with define-macro expresion.
    (define-macro (for params . body)
        `(let iter ((,(car params) ,(cadr params)))
            (if (< ,(car params) ,(caddr params))
                (begin
                    ,@body
                    (iter (+ ,(car params) ,(if (= (length params) 4)
                                                (cadddr params)
                                                1)))))))
    

    The former code define for loop (which use tail recursion), you could use it with (for (variable init end step) code):

    (for (i 1 10)
      (display i)
      (newline))

    or

    (for (i 10 100 10) (display i) (newline))

    Which display numers: 10 20 30 40 50 60 70 80 90 100.

Update: Check also Extending Scheme interpreter in BiwaScheme wiki on GitHub.

,

  1. #1 by kurt on October 24, 2012 - 19:19

    Hey. Thanks for writing this article. But I find that it is not clear enough for a beginner.
    I want to use BiwaScheme as a Scheme interpreter in my page, but I just want to be able to call javascript functions from it.
    For example,

    //scheme
    (define func (draw-circle 10.0))
    func
    

    goes to an input field in my webpage.
    Use then clicks a button.
    It should call a javascript function like “drawCircle(radius)” and draw the cirlce on a canvas.
    I couldn’t fund this in your article.

    It may be covered here, but I am finding it hard to understand it.
    I read through the whole article, but it doesn’t demonstrate what it is supposed to do, with examples.
    Ofcourse I may not be knowledgable enough to grasp your article, but if you could, I would request you to explain those things with clearer examples.
    Thank you :)

  2. #2 by jcubic on November 1, 2012 - 05:54

    I’m bit confuse, you said that you want to have interpreter and then, that you want to have scheme function and execute it onclick event, and that you wrote that function, so it seems that you don’t need interactive interpreter. If you don’t whant to allow users to type scheme code and execute it you only need to eval the code. If you know jQuery you can use my library for jQuery inside biwascheme http://jcubic.pl/jqbiwa.js so you can calll

    (.click ($ "button") (lambda (e) (draw-circle 10.0)))
    

    You can see it in example to my terminal jquery plugin http://terminal.jcubic.pl/examples.php#biwascheme

    PS: I right now play with better lisp (basic scheme) https://github.com/jcubic/nconc (this is my fork with few changes).

  3. #3 by kurt on November 1, 2012 - 12:29

    Hi. Thanks for your reply.
    I don’t completely understand you.
    Let me clarify myself.

    The webpage I create will have a textarea (html textarea). That is where the user types in his code with a “Scheme” like syntax.
    There is a button below the textarea called “Execute/Evaluate”.
    When the user wants to run the code he typed in, he clicks the button.

    I [B]don’t[/B] want his code to get interpreted normally.
    By “normally” I mean, just outputting text results like “mit-scheme” does.
    I don’t want it do just that.

    I want the code to run my Javascript functions, instead.
    Let me explain what I mean by this.

    Assume that there is [B]another[/B] empty text-box in my webpage.
    I want to use this to change the contents of that text box.
    I tell the user that if he uses this function called “change-text”, with a number parameter, in Scheme, it will change the value of the text box.
    Now the user wants to use Scheme to change the textbox value, 10 times.

    Consider this code typed into the code textarea.
    [CODE]
    (define (func count)
    (if ( < count 10)
    ((change-text count) (func (- count 1)))
    )
    )
    ;; the user calls "func" like this :
    (func 1)
    [/CODE]
    As you can see this function is a recursive function and it runs 10 times.
    It calls the "change-text" function each time with the "count" parameter.
    So the text box's value should change with numbers 1, 2, 3, …., 10 and then stop.

    Now how do I change that text-box's value in javascript?
    Like this :
    [CODE]
    function change(str) {
    document.getElementById("text_box").value = str;
    }
    [/CODE]
    But I don't allow the user to use this function directly.
    Instead, I ask him to use the "Scheme" funtion, "change-text" to do this.

    Now when I use BiwaScheme to evaluate the "Scheme" code in the textarea, which the user types in, I want it to be aware that I have some primitive functions like "change-text" which I have provided to the user.
    So when Biwascheme finds, "change-text", it should call the javascript function "change" which sets the value of the text box.
    I don't intend it to be an interpreter that simply returns text outputs. Infact I don't want any text outputs. I just want it to call other JS functions in the background.

    How do I accomplish this?

    Sorry for the long post, but I hope I expressed myself clearly.
    I would really appreciate your help in this regard. :)

    • #4 by jcubic on November 1, 2012 - 13:52

      To define your change-text function you need to call BiwaScheme.define_libfunc method/function. Probably something like:

      BiwaScheme.define_libfunc('change-text', 1, 1, function(args) {
         change(args[0]);
         return BiwaScheme.undef;
      });
      
  4. #5 by kurt on November 2, 2012 - 14:05

    Thank you.
    I couldn’t verify it yet, because I’m trying to just setup a working Scheme text evaluator first.

    I tried this out. But I find that the callback function passed to evaluate, is not called at all. I tried implementing the cod ein this tutorial.
    Here is my code:

    <html>
    <head>
    	<title>Scheme</title>
    	<script type = "text/javascript" src = "http://www.biwascheme.org/repos/release/biwascheme-min.js" ></script>
    	<script type="text/javascript" src="https://raw.github.com/yhara/biwascheme/master/src/development_loader.js"></script>
    	<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
    </head>
    <body>
    	<textarea rows = 20 cols = 50 id = "input"></textarea>
    	<div id = "output">Result should appear here</div>
    	<input type = "button" id = "eval_btn" value = "Evaluate"></input>
    	
    	<script>
    		var intepreter = new BiwaScheme.Interpreter();
    		var input = $("#input");
    		var output = $("#output");
    		function scheme_eval() {
    		    interpreter.evaluate(input.val(), 
    		       function(result) {
    		           if (result != undefined) {
    		           	alert("Evaluating");
    		               result = BiwaScheme.to_write(result);
    		               output[0].innerHTML += '> ' + result;
    		           }
    		 	  });
    		}
    		$("#eval_btn").click(function() {
    		  	scheme_eval();
    		});
    	</script>
    </body>
    </html>
    

    I’ve put the code here
    http://pastebin.com/QuAajf1b
    if you can’t see the code I’ve pasted above.

    There is a textarea with id = input where user types Scheme code.
    There is a div with id = output where the output should go.
    There is button which starts the interpreting.
    But I find that nothing happens when I start the evaluation.
    There is no alert message “Evaluating”.
    Is something wrong in my code?
    I am particularly unsure of what to pass to the evaluate function.
    Will .value() of jquery work?
    I’m lost here.

    • #6 by jcubic on November 2, 2012 - 22:07

      You have a typo:

      var interpreter = new BiwaScheme.Interpreter();
      var input = $("#input");
      var output = $("#output");
      function scheme_eval() {
          interpreter.evaluate(input.val(), 
             function(result) {
                 if (result != undefined) {
                     result = BiwaScheme.to_write(result);
                     output[0].innerHTML += '> ' + result;
                 }
          });
      }
      $("#eval_btn").click(function() {
         scheme_eval();
      });

      and don’t include development_loader.js you already have all biwascheme inside biwascheme-min.js.

  5. #7 by kurt on November 2, 2012 - 18:07

    Wow, I had that problem resolved. Sorry, for this. The issue was, with

    output[0].innerHTML += '> ' + result;

    It should have been :

    output.text(result);

    I read up in the source code of BiwaScheme demo REPL on the main page of BiwaScheme.
    Since you are the author of jQuery terminal, and jQuery terminal is used in it, I wanted to ask you about it.

    The output gets displayed easily.
    But if the input is incorrect (syntactically, gramatically), error messages have to be shown.
    For this, I did ,

    var opc = intepreter.compile(input.val());
    var dump_opc = (new BiwaScheme.Dumper()).dump_opc(opc);
    output[0].innerHTML = dump_opc;
    

    But the problem is the error messages are encoded in some manner.
    I got this as the output when I typed “(efes Awd)” into the input

    [frame
       [refer-global "Awd"
       [argument
       [constant 1
       [argument
       [refer-global "efes"
       [apply]]]]]]
    [halt]]
    

    But when I tried the same in BiwaScheme interpreter, (in the main page biwascheme.org),
    there were error messages like :

    Error: execute: unbound symbol: ''
    Error: execute: unbound symbol: 'Awd'
    

    I looked at the code again. The term.echo somehow displays those messages.
    But I’m not using an REPL. I’m just dealing with a textarea for input code and a div for output.
    How do I use that message to generate a useful message like ?

    Error: execute: unbound symbol: ''
    Error: execute: unbound symbol: 'Awd'
    
    <html>
    <head>
    	<title>Scheme</title>
    	<script type = "text/javascript" src = "http://www.biwascheme.org/repos/release/biwascheme-min.js" ></script>
    	<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
    </head>
    <body>
    	<textarea rows = 20 cols = 50 id = "input" style = "float : left"></textarea>
    	<div id = "output" style = "padding : 20px; margin-left : 30px; float : left; width : 300px; height : 285px; border:1px solid black; ">Result</div>
    	<input type = "button" id = "eval_btn" value = "Evaluate"></input>
    	<script>
    		var intepreter;
    		var input;
    		var output;
    		$(document).ready(
    			function() {
    				intepreter = new BiwaScheme.Interpreter();
    				input = $("#input");
    				output = $("#output");
    		});
    		function unbalanced_parentheses(text_code) {
    			var tokens = (new BiwaScheme.Parser(text_code)).tokens;
    			var parentheses = 0;
    			var brakets = 0;
    			for(var i = 0; i < tokens.length; ++i) {
    				switch(tokens[i]) {
    					case "[": ++brakets; break;
    					case "]": --brakets; break;
    					case "(": ++parentheses; break;
    					case ")": --parentheses; break;
    				}
    			}
    			return parentheses != 0 || brakets != 0;
    		}
    
    		function scheme_eval() {
    			output.css("color", "black");
    			output.text("Result should appear here");
    			if(unbalanced_parentheses(input.val())) {
    				output.css("color", "red");
    				output.text("Unbalanced Parentheses");
    			}
    			else {
    				var opc = intepreter.compile(input.val());
            		  	var dump_opc = (new BiwaScheme.Dumper()).dump_opc(opc);
            		  	output[0].innerHTML = (dump_opc);
            		  	
    				/*intepreter.evaluate(input.val(),
    					function(result) {
    						if(result === BiwaScheme.undef) {
    							output.css("color", "blue");
    							output.text("Nothing to output");
    						}
    						else if (result != undefined) {
    							result = BiwaScheme.to_write(result);
    							output.text(result);
    						}
    				});*/
        			}
    		}
    		$("#eval_btn").click(function() {
    		  	scheme_eval();
    		});
    	</script>
    </body>
    </html>
    

    This is the code I’m using. Is it possible to know when there is an error and when there isn’t?

    • #8 by jcubic on November 2, 2012 - 21:54

      Don’t use dumper code

      var opc = intepreter.compile(input.val());
      var dump_opc = (new BiwaScheme.Dumper()).dump_opc(opc);
      output[0].innerHTML = dump_opc;
      

      and use error callback function

      var bscheme = new BiwaScheme.Interpreter(function(e, state) {
          output[0].innerHTML += e.message + '\n';
      });
      
  6. #9 by kurt on November 5, 2012 - 12:11

    Thanks a lot !
    Your help made a big difference. Everything worked thus far.
    :)

  7. #10 by khalidcode on August 2, 2013 - 12:54

    Hello i was wondering if it were possible to add ‘match’ to Biwascheme in any way possible.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: