Coder Social home page Coder Social logo

lisphp's Introduction

Lisphp

Build Status

Lisphp is a Lisp dialect written in PHP. It was created to be embedded in web services or to be distributed within web applications. For that reason, it implements sandbox environment for security issues and multiple environment instances.

Requirements

It requires PHP 5.3.0 or higher version. It also requires SPL which is available and compiled by default.

Standalone command line interface

There is bin/lisphp, a standalone command line interface. It can take one parameter, the filename of the Lisphp program to be executed.

$ bin/lisphp program.lisphp

You can run the program in sandbox with the option -s.

$ bin/lisphp -s program.lisphp

REPL

If there is no filename in arguments to bin/lisphp, it enters REPL mode.

$ bin/lisphp
>>> (form to evaluate)

Similarly you can specify -s to enter REPL mode in sandbox.

$ bin/lisphp -s
  • >>> is a prompt.
  • ==> is a returned value of evaluation.
  • !!! is a thrown exception.

Simple tutorial

>>> (+ 12 34)
==> 46
>>> (- 1 2)
==> -1
>>> (* 5 6)
==> 30
>>> (/ 30 5)
==> 6
>>> (/ 30 4)
==> 7.5
>>> (% 30 4)
==> 2
>>> (. "hello" "world")
==> 'helloworld'
>>> (define pi 3.14)
==> 3.14
>>> pi
==> 3.14
>>> (float? pi)
==> true
>>> (string? "abc")
==> true
>>> (* pi 10 10)
==> 314

Embed in your app

In order to execute a Lisphp program, an environment instance is required. Environment represents a global state for the program. It includes global symbols, built-in functions and macros. A program to be executed starts from the initialized environment. You can initialize the environment with Lisphp_Environment class.

require 'vendor/autoload.php';
$env = Lisphp_Environment::sandbox();
$program = new Lisphp_Program($lisphpCode);
$program->execute($env);

There are two given environment sets in Lisphp_Environment. One is the sandbox, which is created with the method Lisphp_Environment::sandbox(). In the sandbox mode, programs cannot access the file system, IO, etc. The other set is the full environment of Lisphp, which is initialized with Lisphp_Environment::full(). This environment provides use macro for importing native PHP functions and classes. File system, IO, socket, etc. can be accessed in this full environment. Following code touches file a.txt and writes some text.

(use fopen fwrite fclose)

{let ([fp (fopen "a.txt" "w")])
     (fwrite fp "some text")
     (fclose fp)}

Macro use and from

The full environment of Lisphp provides use macro. It can import native PHP functions and classes.

(use strrev array_sum array-product [substr substring])

It imports by taking function identifiers. Hyphens in identifiers are replaced by underscores. If you supply a list as an argument to use macro, the second symbol becomes the alias of the first function identifier.

(strrev "hello")                #=> "olleh"
(array_sum [array 1 2 3])       #=> 6
(array-product [array 4 5 6])   #=> 120
(substring "world" 2)           #=> "rld"

Wrap identifiers with angle brackets in order to import class. According to the PEAR naming convention for classes, slashes are treated as hierarchical separators, so it gets replaced by underscores.

(use <PDO> Lisphp/<Program>)

Imported classes are applicable and act as instantiating functions. Static methods in imported classes are also imported as well.

(<PDO> "mysql:dbname=testdb;host=127.0.0.1" "dbuser" "dbpass")
(Lisphp/<Program>/load "program.lisphp")

There's also a macro called from. It simplifies the step of importing objects and resolving their names.

(from Lisphp [<Program> <Scope>])

It has the same behavior as the following code which utilizes use.

(use Lisphp/<Program> Lisphp/<Scope>)
(define <Program> Lisphp/<Program>)
(define <Scope> Lisphp/<Scope>)
(define Lisphp/<Program> nil)
(define Lisphp/<Scope> nil)

Define custom functions

There is a macro lambda that creates a new function. It takes parameter list as its first argument, and then a trailing function body.

(lambda (a b) (+ a b))

Functions are also values, so in order to name the function, use define.

(define fibonacci
        {lambda [n]
                (if (= n 0) 0
                    {if (/= n 1)
                        (+ (fibonacci (- n 1))
                           (fibonacci (- n 2)))
                        1})})

Following code defines the same function.

(define (fibonacci n)
        (if (= n 0) 0
            {if (/= n 1)
                (+ (fibonacci (- n 1))
                   (fibonacci (- n 2)))
                1}))

Function body can contain one or more forms. All forms are evaluated sequentially then the evaluated value of the last form is returned.

Plus, of course, it implements lexical scope (that is also known as closure) also.

(define (adder n)
        {lambda [x]
                (setf! n (+ n x))
                n})

Special form define defines global variables (and functions), but setf! modifies local variables. See also let form.

Define custom macros

The built-in macros in Lisphp such as eval, define, lambda, let, if, and, or do not evaluate the form of their arguments'. For example, define takes the name to define as its first argument, but it does not evaluate the name. In the same way, if takes three forms as arguments, but always evaluates only two of those arguments and ignores the other. It is impossible to implement if as a function, because then every argument would have to be evaluated. If you have a case like this, you can try defining a macro.

(define if*
        {macro [let {(cond (eval (car #arguments)
                                 #scope))}
                    (eval (at #arguments (or (and cond 1) 2))
                          #scope)]})

(define quote*
        [macro (car #arguments)])

Quote

There are two ways to quote a form in Lisphp. First is the macro quote, and the other is quote syntax :. (You cannot use the traditional single quotation because it is already being used as a string literal.)

(quote abc)
:abc
(quote (+ a b))
:(+ a b)

Playing with objects

In order to get an attribute of an object, use -> macro. It takes an object as its first argument, and the name of the attribute follows.

(use [dir <dir>])
(define directory (<dir> "/tmp"))
(define handle (-> directory handle))

There is also a syntactic sugar for object attribute chaining.

(-> object attribute names go here)

This form is equivalent to the following PHP expression.

$object->attribute->names->go->here

Instance methods can also be invoked by ->.

((-> object method) method arguments)

This form is equivalent to the following PHP expression.

$object->method($method, $arguments)

Because -> does not call but gets method as a function object, the expression above is equivalent to the following code.

call_user_func(array($object, 'method'), $method, $arguments)

About lists and nil

Lisphp implements lists in primitive, but it has some differences between original Lisp. In original Lisp, lists are made from cons pairs. But lists in Lisphp is just an instance of Lisphp_List class, a subclass of ArrayObject. So it is not exactly a linked list but is similar to an array. In the same manner, nil is also not an empty list in Lisphp unlike in the original Lisp. It is a just synonym for PHP null value.

About value types and reference types

In PHP, primitive types such as boolean, integer, float, string, and array behave as value types. They are always copied when they are passed as arguments or returned from a called function. For example, arr is empty from the beginning to the end in the following code.

(define arr (array))
(set-at! arr "element")

Such behavior is not a problem for scalar types like boolean, integer, float, and string because they are immutable. Yet this can be problematic for native arrays.

In PHP, objects behave as reference types, and there exists class ArrayObject which has the same interface as PHP's native array. Lisphp_List is a subclass of ArrayObject and you can use these classes instead of arrays.

(use <ArrayObject>)
(define arr (<ArrayObject>))
(set-at! arr "element")
(define lis (list))
(set-at! arr "element")

Mailing list

There is the mailing list to discuss about Lisphp: [email protected].

The web archive for this mailing list: http://groups.google.com/group/lisphp.

Author and license

Lisphp was written by Hong Minhee http://dahlia.kr/.

Lisphp is distributed under the MIT license.

lisphp's People

Contributors

dahlia avatar igorw avatar pborreli avatar

Stargazers

Masanori Ogino avatar geduardcatalindev avatar Cesar Marinho avatar Thiago Carvalho avatar  avatar Jorge Gomez avatar William Perreault avatar  avatar  avatar Wang Chao avatar Kaeland Chatman avatar  avatar Chuck Adams avatar Michael Rubanov avatar Javier Vivanco avatar Rishi avatar Ben avatar 秋 奈月 avatar royee avatar Stone Penn avatar Legend avatar  avatar 周晶 avatar Federico Cagliero avatar baijunyao avatar Panda avatar  avatar jefurry avatar  avatar  avatar Ilhan Yumer avatar X Caminhante avatar Jarkko Saltiola avatar  avatar chenhong avatar Lovenunu avatar  avatar Peter Fisk avatar Jeremie Jarosh avatar Chris Fasel avatar Sérgio R Siqueira avatar Usama Ejaz avatar Sonishi Izuka avatar  avatar Apollia avatar  avatar Angus H. avatar kazuhiro hara avatar Alexander Wühr avatar Vasya Poteryaiko avatar  avatar Petr Myazin avatar Fabio Ribeiro avatar Marcus Sá avatar Dmitry Khomutov avatar Fabien Salathe avatar MarQuis Knox avatar Hugo Estrada avatar Robin avatar kissthink avatar Bremen (Luke) Braun avatar  avatar Roman Zaykin avatar  avatar  avatar Mayra Valdés avatar Saji Nediyanchath avatar Alexander V. Nikolaev avatar  avatar Juan Serrats avatar スコット avatar Marcus avatar peterwang avatar Vineet Naik avatar Fogus avatar Alan Dipert avatar Stev Leibelt avatar  avatar phairow avatar Marcelo Camargo avatar Bartosz Cytrowski avatar Ramon Barros avatar Sean Huber avatar Povilas Skruibis avatar Ciaran Downey avatar Joy Nag avatar Feng avatar Jonathan H. Wage avatar Chris avatar Ivan Enderlin avatar Carsten Brandt avatar uzulla / Junichi Ishida avatar  avatar Necat Bolpaça avatar  avatar yunshang avatar Michael Wong avatar weakish avatar  avatar HaraShun avatar

Watchers

 avatar M. David Peterson avatar Lars Strojny avatar  avatar Gabriel Oliveira avatar 南無假行僧 avatar Kenneth Rapp avatar James Cloos avatar  avatar Roman Zaykin avatar  avatar  avatar

lisphp's Issues

Rename macro to fexpr

The macros are not actually macros but fexprs. They do not operate on the source AST at compile time, but instead interpret it at runtime.

Therefore it would make sense to either replace them with real macros or rename them to fexprs.

Implement EDN

Clojure's extensible data notation.

Should probably be released as a separate, standalone library under the lisphp namespace. Future versions of lisphp can then re-use parts of it. Possibly there should be a lisphp/common package which defines data types (symbols, keywords) and other re-usable parts.

Error handling

Some sort of error handling, perhaps some kind of try..catch.

Support scheme-style quoting

Scheme-style quoting with the ' char is currently not possible because both ' and " are supported for strings. Instead : is used. It would be nice to support classic style quoting, and enforcing double quotes for strings is quite acceptable.

Before:

(:foo :(bar baz) "qux" 'quux')

After:

('foo '(bar baz) "qux" "quux")

Short list and hashmap syntax

Might be nice to have [] for lists and {} for assoc arrays:

[1 2 3]
=>
array(1, 2, 3)

{:foo "bar"
 :baz "qux"}
=>
array('foo' => 'bar', 'baz' => 'qux')

This is similar to how clojure works.

Comments

It should be possible to comment out lines using semicolons:

; add two numbers
(+ 1 2)

Pattern matching

Clojure example:

(defn numbers [x]
  (match [x]
     [1] :one
     [2] :two
     [_] :many))

(if true 'Yep') issue

I forked this project yesterday. I still dont know if this is supposed to be ok as I never worked with lisp before. The issue appeared when running these examples:

(if true "Yep")
(if true 'Yep')

The first example work as expected, by returning 'Yep' (or so i suppose). The second one shows an error. I tried to figure it out by myself and I think I found the reason. Looks like the problem is related to the regex used to parse a string literal. The solution came after replacing

const STRING_PATTERN = '/^"([^"\\]|\.)"|'([^\'\\]|\.)'/';

with

const STRING_PATTERN = '/^"([^"\\]|\.)"|^'([^\'\\]|\.)'/';

in the Parser class (notice the additional ^ symbol right after the second pipe).

Extending the scope at the php level

For example to add stuff that is not possible in lisphp userland. Ideally this could be done at the per-project level, and lisphp would automatically load the files.

Short function syntax

Similar to clojure's fn:

(def hello (fn [] "Hello world"))

Or more complex:

(defn make-adder [x]
  (let [y x]
    (fn [z] (+ y z))))
(def add2 (make-adder 2))
(add2 4)

Partial func application

Pre-fill args:

(define data (array "foo" "bar" "baz"))
(map (partial at data) [0 2])
; => ["foo" "baz"]

Pass values by reference when needed

For example:

(use reset)
(define (first-element ary)
    (reset ary))
(first-element (array 1 2 3))

Currently fails because reset expects a reference.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.