package Language::LispPerl;
$Language::LispPerl::VERSION = '0.007';
use 5.008008;
use strict;
use warnings;

use Language::LispPerl::Evaler;

sub true{ return Language::LispPerl::Evaler->true(); }
sub false{ return Language::LispPerl::Evaler->false(); }
sub nil{ return Language::LispPerl::Evaler->nil(); }
sub empty_list{ return Language::LispPerl::Evaler->empty_list(); }

1;

__END__

=head1 NAME

Language::LispPerl - A lisp in pure Perl with perl bindings.

=head1 SYNOPSIS

  use Language::LispPerl::Evaler;

  my $lisp = Language::LispPerl::Evaler->new();

  # Load core functions and macros
  $lisp->load("core.clp");

  my $res = $lisp->eval(q|
        (defmacro defn [name args & body]
          `(def ~name
             (fn ~args ~@body)))

        (defn foo [arg]
          (println arg))

        (foo "hello world!") ;comment here
      |);

  # $res is the last lisp object evaluated.

=head1 DESCRIPTION

Language::LispPerl is a pure Perl lisp interpreter.
It is a fork of L<CljPerl> that focuses on making embedding
lisp code in your Perl written software straightforward.

=head1 INCOMPATIBILITIES

=over

=item From version 0.004

This uses L<Moose> instead of L<Moo>. This should not have any impact on your code,
except if you have written your own role for 'Language::LispPerl::BuiltIns'. It will need to be a L<Moose::Role>
instead of a L<Moo::Role>.

=back

=head2 BINDING Perl functions to Lisp

=head3 Lisp <-> Perl

Here is how to bind to your own Perl functions from lisp.

This assumes that your perl functions live in My::App::LispFunctions

=head4 PURE Perlfunctions in My::App::LispFunctions:

	package My::App::LispFunctions;

	sub do_stuff {
       my ($x , $y ) = @_;
       ..
       return;
	}

    sub say_stuff {
       my ($x , $y ) = @_;
       ..
       return $string_or_number;
    }

	sub is_stuff {
       ..
       # Note that here we return a raw lisp object.
       return Language::LispPerl->true();
	}

=head4 Binding to these functions in myapp.clp (living in share/lisp for instance):

     ;; These lisp binding functions will live
     ;; in the namespace 'myapp'

     ;; Note that you need core.clp to be loaded in the Evaler.

     (ns myapp
       (. require My::App::LispFunctions)

       (defn do-stuff [x y]
	      (.My::App::LispFunctions do_stuff  ^{:return "nil"}  x y ))

       (defn say-stuff [x y]
	    (.My::App::LispFunctions say_stuff ^{:return "scalar"} x y ))

	   (defn is-stuff [x y]
	    (.My::App::LispFunctions is_stuff ^{:return "raw"} x y)))

=head4 Usage in lisp space:

     ( require "myapp.clp" ) ;; Or in Perl $lisp->load("myapp.clp");
     ( myapp#do-stuff .. .. ) ;; Note the myapp# namespace marker.


=head3 Importing and using any Perl package (without prior binding)

=head4 An example which creates a timer with AnyEvent.

	(. require AnyEvent)

	(def cv (->AnyEvent condvar))

	(def count 0)

	(def t (->AnyEvent timer
	  {:after 1
	   :interval 1
	   :cb (fn [ & args]
	         (println count)
	         (set! count (+ count 1))
	         (if (>= count 10)
	           (set! t nil)))}))

	(.AnyEvent::CondVar::Base recv cv)

=head3 Implemeting your own native Lisp functions

.TBC.

=head3 This lisp implementation

=head4 Atoms

 * Reader forms

   * Symbols :

	foo, foo#bar

   * Literals

   * Strings :

	"foo", "\"foo\tbar\n\""

   * Numbers :

	1, -2, 2.5

   * Booleans :

	true, false . Or from Perl: Language::LispPerl->true() and Language::LispPerl->false()

   * Nil :

        nil . Or from Perl: Language::LispPerl->nil();

   * Keywords :

	:foo

 * Lists :

	(foo bar)

 * Vectors :

	[foo bar]

 * Maps :

	{:key1 value1 :key2 value2 "key3" value3}


=head4 Macro charaters

 * Quote ('). :

	'(foo bar)

 * Comment (;) :

	; comment

 *  Dispatch (#) :

   * Accessor (:) :

	#:0 ; index accessor
	#:"key" ; key accessor
	#::key  ; key accessor

   * Sender (!) :

	#!"foo"

   * XML ([) :

	#[body ^{:attr "value"}]

 * Metadata (^) :

	^{:key value}

 * Syntax-quote (`) :

	`(foo bar)

 * Unquote (~) :

	`(foo ~bar)

 * Unquote-slicing (~@) :

	`(foo ~@bar)

=head4 Builtin  lisp Functions

 * list :

	(list 'a 'b 'c) ;=> '(a b c)

 * car :

	(car '(a b c))  ;=> 'a

 * cdr :

	(cdr '(a b c))  ;=> '(b c)

 * cons :

	(cons 'a '(b c)) ;=> '(a b c)

 * key accessor :

	(#::a {:a 'a :b 'a}) ;=> 'a

 * keys :

	(keys {:a 'a :b 'b}) ;=> (:a :b)

 * index accessor :

	(#:1 ['a 'b 'c]) ;=> 'b

 * sender :

	(#:"foo" ['a 'b 'c]) ;=> (foo ['a 'b 'c])

 * xml :

	#[html ^{:class "markdown"} #[body "helleworld"]]

 * length :

	(length '(a b c)) ;=> 3
	(length ['a 'b 'c]) ;=> 3
	(length "abc") ;=> 3

 * append :

	(append '(a b) '(c d)) ;=> '(a b c d)
	(append ['a 'b] ['c 'd]) ;=> ['a 'b 'c 'd]
	(append "ab" "cd") ;=> "abcd"

 * type :

	(type "abc") ;=> "string"
	(type :abc)  ;=> "keyword"
	(type {})    ;=> "map"

 * meta :

	(meta foo ^{:m 'b})
	(meta foo) ;=> {:m 'b}

 * fn :

	(fn [arg & args]
	  (println 'a))

 * apply :

	(apply list '(a b c)) ;=> '(a b c)

 * eval :

	(eval "(+ 1 2)")

 * require :

	(require "core")

 * def :

	(def foo "bar")
	(def ^{:k v} foo "bar")

 * set! :

	(set! foo "bar")

 * let :

	(let [a 1
	      b a]
	  (println b)) 

 * defmacro :

	(defmacro foo [arg & args]
	  `(println ~arg)
	  `(list ~@args))

 * if :

	(if (> 1 0)
	  (println true)
	  (println false))

	(if true
	  (println true))

 * while :

	(while true
	  (println true))

 * begin :

	(begin
	  (println 'foo)
	  (println 'bar))

 * perl->clj :

 * ! not :

	(! true) ;=> false

 * + - * / % == != >= <= > < : only for number.

 * eq ne : only for string.

 * equal : for all objects.

 * . : (.[perl namespace] method [^meta] args ...)
	A meta can be specifed to control what type of value should be passed into perl function.
	type : "scalar" "array" "hash" "ref" "nil"
	^{:return type
	  :arguments [type ...]}

	(.Language::LispPerl print "foo")
	(.Language::LispPerl print ^{:return "nil" :arguments ["scalar"]} "foo") ; return nil and pass first argument as a scalar

 * -> : (->[perl namespace] method args ...)
   Like '.', but this will pass perl namespace as first argument to perl method.

 * println

	(println {:a 'a})

 * trace-vars : Trace the variables in current frame.

	(trace-vars)

 * quote : Returns the given list as is without evaluating it

    (quote (+ 1 2 )) -> (+ 1 2)

=head4 Core Functions (defined in core.clp)

 * use-lib : append path into Perl and Language::LispPerl files' searching paths.

	(use-lib "path")

 * ns : Language::LispPerl namespace.

	(ns "foo"
	  (println "bar"))

 * defn :

	(defn foo [arg & args]
	  (println arg))

 * defmulti :

 * defmethod :

 * reduce :

 * map :

 * file#open : open a file with a callback.

	(file#open ">file"
	  (fn [fh]
	    (file#>> fn "foo")))

 * file#<< : read a line from a file handler.

	(file#<< fh)

 * file#>> : write a string into a file handler.

	(file#>> fh "foo")

=head1 PERSISTENCE

Since V0.007, you have the possibility to 'freeze' the evaler into a pure perl data structure,
and defrost it later on to execute some code in the same evaler state.

Usage:

  my $lisp = Language::LispPerl::Evaler->new();
  # Load core functions and macros
  $lisp->load("core.clp");
  $lisp->eval(q|(defn square [a] ( * a a ))|);

  my $perl_hash = $lisp->to_hash();
  # Store this pure perl hash somewhere in your favourite format.
  # Hint: compress its representation as it can be quite big.

  # Then later on:
  my $new_lisp = Language::LispPerl::Evaler->from_hash( $perl_hash );
  my $res = $new_lisp->eval(q|(square 2 )|);

=head1 SEE ALSO

L<CljPerl>

=head1 AUTHOR

Current author: Jerome Eteve ( JETEVE )

Original author: Wei Hu, E<lt>huwei04@hotmail.comE<gt>

=head1 COPYRIGHT

Copyright 2016-2017 Jerome Eteve. All rights Reserved.

Copyright 2013 Wei Hu. All Rights Reserved.

=head1 ACKNOWLEDGEMENTS

This package as been released with the support of L<http://broadbean.com>

=head1 LICENSE

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=cut
