diff --git a/build.sbt b/build.sbt index 922d948..2468561 100644 --- a/build.sbt +++ b/build.sbt @@ -3,17 +3,16 @@ name:="termware" organization:="com.github.termware" -scalaVersion := "2.10.0-M6" +scalaVersion := "2.12.1" scalacOptions ++= Seq("-unchecked","-deprecation","-feature") version:="0.0.2" -libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.10.0-M6" - -// hack to support scalatest -libraryDependencies += "org.scalatest" %% "scalatest" % "1.9-2.10.0-M6-B2" % "test" +libraryDependencies <+= (scalaVersion){ "org.scala-lang" % "scala-reflect" % _ } +libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test" +//libraryDependencies += "com.github.rssh" %% "trackedfuture" % "0.3" % "test" publishMavenStyle := true diff --git a/doc/stermware.bib b/doc/stermware.bib new file mode 100644 index 0000000..3ae1183 --- /dev/null +++ b/doc/stermware.bib @@ -0,0 +1,79 @@ + +@ARTICLE{Klop93combinatoryreduction, + author = {Jan Willem Klop and Vincent van Oostrom and Femke van Raamsdonk}, + title = {Combinatory Reduction Systems: introduction and survey}, + journal = {THEORETICAL COMPUTER SCIENCE}, + year = {1993}, + volume = {121}, + pages = {279--308} +} + + +@article{DBLP:journals/fuin/DoroshenkoS06, + author = {Anatoly E. Doroshenko and + Ruslan Shevchenko}, + title = {TermWare: A Rewriting Framework for Rule-Based Programming Dynamic Applications}, + journal = {Fundam. Inform.}, + volume = {72}, + number = {1-3}, + pages = {95--108}, + year = {2006}, + url = {http://content.iospress.com/articles/fundamenta-informaticae/fi72-1-3-08}, + timestamp = {Mon, 18 May 2015 17:23:19 +0200}, + biburl = {http://dblp.uni-trier.de/rec/bib/journals/fuin/DoroshenkoS06}, + bibsource = {dblp computer science bibliography, http://dblp.org} +} + +@INPROCEEDINGS{Jay05purepattern, + author = {C. Barry Jay and Delia Kesner}, + title = {Pure Pattern Calculus}, + booktitle = {ACM Trans. Program. Lang. Syst}, + year = {2005}, + pages = {262--274}, + url = {http://www.pps.univ-paris-diderot.fr/~kesner/papers/revisedpurepattern.pdf} +} + +@INPROCEEDINGS{RhoCal-Wrla2002, + author = {Cirstea,~Horatiu and Kirchner,~Claude and Liquori,~Luigi}, + title = {Rewriting Calculus with(out) Types}, + booktitle = {Proceedings of the fourth workshop on rewriting logic + and applications}, + year = {2002}, + editor = {Gadducci, Fabio and Montanari, Ugo}, + publisher = {Electronic Notes in Theoretical Computer Science}, + address = {Pisa (Italy)}, + month = SEP, +} + +@article{BravenboerKVV08, + title = {{Stratego/XT 0.17}. {A} language and toolset for program transformation}, + author = {Martin Bravenboer and Karl Trygve Kalleberg and Rob Vermaas and Eelco Visser}, + year = {2008}, + doi = {http://dx.doi.org/10.1016/j.scico.2007.11.003}, + tags = {control systems, programming languages, object-oriented programming, concrete object syntax, reusable components, rule-based, completeness, meta programming, pattern language, graph transformation, Stratego/XT, transformation language, reuse, graph-rewriting, rules, transformation system, DSL, programming, subject-oriented programming, context-aware, abstraction, Meta-Environment, rewriting, rewriting strategies, feature-oriented programming, concrete syntax, meta-objects, transformation, Stratego, program transformation}, + researchr = {http://researchr.org/publication/BravenboerKVV08}, + cites = {0}, + citedby = {7}, + journal = {Science of Computer Programming}, + volume = {72}, + number = {1-2}, + pages = {52-70}, +} + +@inproceedings{Pfenning:1988:HAS:53990.54010, + author = {Pfenning, F. and Elliott, C.}, + title = {Higher-order Abstract Syntax}, + booktitle = {Proceedings of the ACM SIGPLAN 1988 Conference on Programming Language Design and Implementation}, + series = {PLDI '88}, + year = {1988}, + isbn = {0-89791-269-1}, + location = {Atlanta, Georgia, USA}, + pages = {199--208}, + numpages = {10}, + url = {http://doi.acm.org/10.1145/53990.54010}, + doi = {10.1145/53990.54010}, + acmid = {54010}, + publisher = {ACM}, + address = {New York, NY, USA}, +} + diff --git a/doc/stermware.tex b/doc/stermware.tex new file mode 100644 index 0000000..621b0ba --- /dev/null +++ b/doc/stermware.tex @@ -0,0 +1,227 @@ +\title{STermWare: brief semantics description} +\author{ + Ruslan Shevchenko \\ + ruslan@shevchenko.kiev.ua\\ + Kiev, Ukraine +} +\date{\today} + + + +\documentclass[12pt]{article} +\usepackage{listings} +\usepackage{amsmath} +\usepackage{pgf} +\usepackage{tikz} +\usetikzlibrary{arrows,automata} + +% "define" Scala +\lstdefinelanguage{scala}{ + morekeywords={abstract,case,catch,class,def,% + do,else,extends,false,final,finally,% + for,if,implicit,import,match,mixin,% + new,null,object,override,package,% + private,protected,requires,return,sealed,% + super,this,throw,trait,true,try,% + type,val,var,while,with,yield}, + otherkeywords={=>,<-,<\%,<:,>:,\#,@}, + sensitive=true, + morecomment=[l]{//}, + morecomment=[n]{/*}{*/}, + morestring=[b]", + morestring=[b]', + morestring=[b]""" +} + + + +\begin{document} +\maketitle + +\begin{abstract} + Termware is a term rewriting system which implemented as internal and external DSL. +\end{abstract} + +\section{Motivation} + + Rule-based deduction and rewriting is a well known techniques. Exists many formalizations, from + equational logic to $\rho$-caclulus \cite{RhoCal-Wrla2002} and pure pattern calculus\cite{Jay05purepattern} Few programming languages are build on top of rule rewriting technique. + + We need compact and clean formalizm for definition of programming language construction. Classical term + rewriting can be used for describing program transformations 'in small', but leave dealing with context out + of scope of analysis. Exists different approaches for solving such issues: program analyzers based on + termware framework \cite{DBLP:journals/fuin/DoroshenkoS06} uses terms enriched by context parameters wich provide + API for quering semantics properties, Statego\cite{BravenboerKVV08} use dynamic context-specific rules. + + Another approaches is hight order abstract syntax\cite{Pfenning:1988:HAS:53990.54010}: AST with binding information encoded as lambda terms, where binded names represented as binded variables. + + Our proposed approach is an algebra of context-depended term, where operations under term with context are expressed in explicit form. + +\section{Basic definitions} + + Let's build term algebra on top of some set of constants, which constists from +\begin{itemize} + \item original constants ${c_i} \in C$ Also we + will need to distinguish some special subset of constants: atoms ${a_i}$ and also have some special set +of atoms. + \item functional term $f_i \in F$ i.e. if $f \in F, c_i \in T (i \in 1..n)$, then $f(c_{1} \dots c_{n}) \in T$ + %\item variable terms $x_{i}$ which can be inside variable-bound terms. + \item rule terms in form $\eta x_1 \dots x_n : p_{1} \to r_1 | p_2 \to r_2 | \dots ! p_{k}$ + %\item variable bounds term, i.e. so-called 'with-expressions': $with(x_1 \to t_i,\dots x_n\to t_n):t$ + %\item rule terms, i. e. so-called 'rule expressions': + % $rule(p_1 \to r_1; p_2 \to r_2 ; \dots p_n \to r_n : p_{fail})$ + \item application $a b$ + \item context-terms in form of $context(a,b)$ where $a$ is $rule-term$ which can be delayed operation + \item set-term $\{ t_1 \dots t_2 \}$ which define set of term. Also, let's define special atom for empty + set: $\emptyset$ and for universum $U$ +\end{itemize} + + And set of usual term operations: + \begin{itemize} + \item subterm: + $$ \left.\begin{array}{l} + subterm(f(t_1,..t_n),i)=x_i \\ + subterm(context(S,t),i)=context(S,subterm(t,i)) \\ + subterm(\{t_1 \dots t_n \},i)=\{subterm(t_1,i), \dots subterm(t_n,i)\} \\ + subterm(F,i)=\emptyset \\ + \end{array}\right. + $$ + \item union: $ x | y = \{ x, y \}$ + $$ \left.\begin{array}{l} + x | \emptyset = x \\ + U | x = U \\ + {x | x } = x \\ + \{ x \to a, x \to b \} = x \to \{a,b\} \\ + \{ x \to a, y \to a \} = \{ x, y\} \to a \\ + context(c,x) | context(c,y) = context(c, x|y) \\ + \end{array}\right. + $$ + also we will identify term and one-element set. + + \item intersection: $ x \& y $ + $$ \left.\begin{array}{l} + x \& \emptyset = \emptyset \\ + U \& x = x \\ + {x \& x } = x \\ + x \to a \& x \to b = x \to a \& b \\ + (a | b ) \& c = a\& c | b\&c \\ + (a \& b ) | c = a\& c | b\&c \\ + \end{array}\right. + $$ + Also usefule will be notation $\langle x_1 \dots x_n \rangle$ wich we will call 'compatible set'. + + + \item substitution and unification: + Note, that in out formalizm substitution and unification results can be represented as ordinary terms + (set of arrows). Also note, that we can any term $t$ repesent as arrow $\emptyset \to t$, by + (let's name on 'substituion term') + $$ subst(x,y) = + \left\{\begin{array}{l l l } + x=\emptyset & & \emptyset \\ + & y=\emptyset & x \\ + x & y=a_{y} \to b_{y} & subst(b_{y},unify(x,a_{y})) \\ + \end{array}\right. + $$ + + $$ unify(x,y) = + \left\{\begin{array}{l l l } + x=\emptyset & & \emptyset \\ + x & \emptyset & \emptyset \\ + c_i \in C & c_j \in C & c_i == c_j \\ + a -> b & & \\ + \end{array}\right. + $$ + + \end{itemize} + + + Transformations: + +\begin{itemize} + \item application reduction + $$ (\eta x_j : p_i \to r_i| \dots ! p_{fail} ) q = + \left\{\begin{array}{l l} + \sigma r_i & \text{if $\sigma=\text{unify}(p_i,q)/x_{i}$} \\ + p_{fail} & otherwise \\ + \end{array} + \right\} + $$ + \item application + $$ + (a->b) c = \left\{ + \begin{array}{l l} + sigma b & \text{ if $\sigma=\text{unify}(a,c) $ } + \end{array}{l l} + \right\} + $$ +\end{itemize} + + +\subsection{ Matching Net } + + For effecient + +for example, next term + +$$ + \begin{aligned} + \eta x, y: & f(x,g(y),x) \to {p_1}(x,y) | \\ + & f(x,x,x) \to {p_2}(x) | \\ + & f(x,y,x) \to {p_3}(x,y) | \\ + & g(y) \to y | \\ + & x \to A \\ + \end{aligned} +$$ + + will be represented by matching net, shown below: + +\begin{tikzpicture}[->,>=stealth',auto,node distance=2.5cm] + + \node(initial, state) (I) { $I$ }; + \node(state) (3) [below right of=I] { $*(*,*,*)$ }; + \node(state) (3fx) [below of=3] { $f(x,*,*)$ }; + \node(state) (3fx1) [below right of =3fx ] { $f(x,*(*),*)$ }; + \node(state) (3fx1gy) [below of =3fx1 ] { $f(x,g(y),*)$ }; + \node(state) (3fx1gyx) [below right of=3fx1gy] {$f(x,g(y),x) \to p_1(x,y)$ }; + \node(state) (3fxx) [below left of=3fx] { $f(x,x,*)$ }; + \node(state) (3fxxx) [below left of=3fxx] { $f(x,x,x) \to p_2(x)$ }; + \node(state) (3fxy) [below of=3fxx] { $f(x,y,*)$ }; + \node(state) (F) [right of=3] { $x \to A$ }; + \node(state) (3fxyx) [ below of=3fxy ] { $f(x,y,x)\to p_3(x,y)$ }; + + + \node(state) (1) [below left of=I] { $*(*)$ }; + \node(state) (1gy) [below left of=1] { $g(y) \to y$ }; + + + \path[font=\scriptsize] + (I) edge node { arity=3 } (3) + edge node { arity=1 } (1) + edge [dotted] node { } (F) + (3) edge node { $name=f$ } (3fx) + edge [dotted] node { } (F) + (3fx) edge node { $2:arity=1$ } (3fx1) + edge node { $2:unify(x)$ } (3fxx) + edge [dotted] node { } (3fxy) + (3fxx) edge node { $3:unify(x)$} (3fxxx) + edge [bend left,dotted] node { } (F) + (3fx1) edge node {2:name==g } (3fx1gy) + edge [bend left, dotted] node { } (3fxy) + (3fxy) edge node {$3:unify(x)$} (3fxyx) + edge [bend left,dotted] node { } (F) + (3fx1gy) edge node {3:unify(x)} (3fx1gyx) + edge [bend right,dotted] node { } (F) + (1) edge node {$name=g$} (1gy) + edge [bend right,dotted] node {fail} (F) + + ; + +\end{tikzpicture} + + Here, each node match imply one lookup (via arity or via name) and then match the rest of target term with the received node; on success we will reach termination node; on failure -- exclude looked patch from possible termination and retry unification until termination patch will be found or all possible forward patched exhausted. If not forward unification is possible in the given node - navigate to next candidate via fallback edge (which are shown as dotted on the scheme). + + +\bibliographystyle{abbrv} +\bibliography{stermware} + +\end{document} diff --git a/project/plugins.sbt b/project/plugins.sbt index b4e3b0c..0d469ac 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,5 @@ resolvers += Classpaths.typesafeResolver -addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0") +addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.3.0") diff --git a/src/main/scala/termware/ArrowTermOps.scala b/src/main/scala/termware/ArrowTermOps.scala new file mode 100644 index 0000000..6cb9be1 --- /dev/null +++ b/src/main/scala/termware/ArrowTermOps.scala @@ -0,0 +1,13 @@ +package termware + +trait ArrowTermOps extends TermOps { + + this: ArrowTerm => + + override def name = ArrowName + + override def cardinality = TermCardinality.ONE + + + +} diff --git a/src/main/scala/termware/AtomTermOps.scala b/src/main/scala/termware/AtomTermOps.scala new file mode 100644 index 0000000..d538bc3 --- /dev/null +++ b/src/main/scala/termware/AtomTermOps.scala @@ -0,0 +1,13 @@ +package termware + + +trait AtomTermOps extends UniTermOps +{ + this: AtomTerm => + + override val name = AtomName(value) + + override def arity: Int = 0 + + override def uniTerm() = this +} diff --git a/src/main/scala/termware/CallCCThrowable.scala b/src/main/scala/termware/CallCCThrowable.scala deleted file mode 100644 index af2344f..0000000 --- a/src/main/scala/termware/CallCCThrowable.scala +++ /dev/null @@ -1,12 +0,0 @@ -package termware; - -import scala.util.control.ControlThrowable; - -class CallCCThrowable[A](val trampolineId:TrampolineId, - val current:ComputationBounds[A]) - extends ControlThrowable -{ - def tid = trampolineId -} - - diff --git a/src/main/scala/termware/CharTermOps.scala b/src/main/scala/termware/CharTermOps.scala new file mode 100644 index 0000000..69e210a --- /dev/null +++ b/src/main/scala/termware/CharTermOps.scala @@ -0,0 +1,9 @@ +package termware + +trait CharTermOps extends TermOps +{ + this: CharTerm => + + override val name = CharName(value) + +} diff --git a/src/main/scala/termware/ComputationBounds.scala b/src/main/scala/termware/ComputationBounds.scala deleted file mode 100644 index 90cf542..0000000 --- a/src/main/scala/termware/ComputationBounds.scala +++ /dev/null @@ -1,259 +0,0 @@ -package termware; - -import scala.reflect.runtime.universe._ -import scala.concurrent._ - - -/** - * result of 'computation chunk' in trampoline. - **/ -sealed abstract class ComputationBounds[+A] -{ - - thisComputationBounds => - - import ComputationBounds._ - - /** - * true when we have result. - */ - def isDone: Boolean; - - /** - * resutl of computations. - */ - def result: Option[A] - - // receive next computation bounds if we not done. - def step(tid:TrampolineId, depth:Int): ComputationBounds[A] - - - def toFuture(implicit executor:ExecutionContext): Future[A] = - future{ trampoline(this); } - - // Monadic syntax - - - def get: A = trampoline(this); - - def map[B](f: A => B): ComputationBounds[B] = flatMap((x:A) => Done(f(x))) - - - def flatMap[B](f: A => ComputationBounds[B]) = - compose(this, (a:A)=>f(a)) - - /** - * monadic interface where client can see trampolineId and depth. - **/ - class InProcess { - - def map[B](f: A => (TrampolineId,Int) => B): ComputationBounds[B] = - flatMap(x => (tid,depth) => Done(f(x)(tid,depth))) - - def flatMap[B](f: A => (TrampolineId,Int) => ComputationBounds[B]) = - compose(thisComputationBounds, (tid,depth,a:A)=>f(a)(tid,depth)) - - - } - - def inProcess = new InProcess - -} - - - -/** - * when we have some result. - **/ -case class Done[A](val r: A) extends ComputationBounds[A] -{ - def isDone: Boolean = true; - def result: Option[A] = Some(r); - def step(tid:TrampolineId, depth:Int) = this; -} - -/** - * when we need to call net thunk - **/ -case class Call[A]( - thunk: (TrampolineId, Int) => ComputationBounds[A] - ) extends ComputationBounds[A] -{ - def isDone: Boolean = false; - def result: Option[A] = None; - def step(tId:TrampolineId,depth:Int) = { - thunk(tId,depth); - } -} - -object Call -{ - - def nested[A](tid:TrampolineId, nesting:Int)(block : ((TrampolineId,Int) => ComputationBounds[A])) = - if (nesting > ComputationBounds.MAX_NESTING) { - throw new CallCCThrowable(tid,Call{block}) - } else { - block(tid,nesting+1); - } - -} - - - -case class Compose[A,B] private[termware](source:ComputationBounds[A], - conts: ComputationBounds.Cont[A,B] - ) extends ComputationBounds[B] -{ - import ComputationBounds._ - - def isDone: Boolean = false; - - def result: Option[B] = None; - - def step(tid:TrampolineId, depth:Int) = { - source match { - case Done(a) => - conts match { - case ContOne(f,n) => - try { - f(tid,depth,a) - } catch { - case ex:CallCCThrowable[B] if ex.tid == tid => - ex.current - } - case ContCons(f,g) => - f match { - case ContOne(ff,fdepth) => - var s = try { - ff(tid,depth,a) - } catch { - case ex:CallCCThrowable[_] if ex.tid == tid => - ex.current - } - s match { - case Done(_) => Compose(s,g) - case Call(_) => Compose(s,g) - case Compose(s,f1) => Compose(s,append(f1,g)) - } - case ContCons(f1,f2) => - Compose(source,ContCons(f1,ContCons(f2,g))) - } - } - case Call(_) => - val r = source.step(tid,depth); - r match { - case Done(x) => Compose(r,conts) - case Call(_) => Compose(r,conts) - case Compose(s,f1) => Compose(s,append(f1,conts)) - } - case Compose(s,f1) => Compose(s,append(f1,conts)) - } - } - -} - - -object ComputationBounds -{ - - - def trampoline[A](cb:ComputationBounds[A]):A = { - val trampolineId = TrampolineId.next - var current = cb; - while (!current.isDone) { - current = try { - current.step(trampolineId, 0) - } catch { - case ex : CallCCThrowable[_] if (ex.trampolineId == trampolineId) - => ex.current.asInstanceOf[ComputationBounds[A]] - } - } - current.result.get - } - - def doStep[A](cb:ComputationBounds[A])(trampolineId: TrampolineId, depth:Int):ComputationBounds[A] = - { - if (cb.isDone) { - cb - } else { - try { - cb.step(trampolineId, depth) - } catch { - case ex : CallCCThrowable[_] if (ex.trampolineId == trampolineId) - => ex.current.asInstanceOf[ComputationBounds[A]] - } - } - } - - sealed trait Cont[A,+B] - { - type From = A; - type To = B; - } - - case class ContOne[A,B](f: (TrampolineId,Int,A)=> ComputationBounds[B], n: Int = 0) extends Cont[A,B] - - case class ContCons[A,B,C](val x:Cont[A,B], - val y:Cont[B,C]) extends Cont[A,C] - - type ~>[A,B] = Cont[A,B] - - def append[A,B,C](f: A ~> B, g: B ~> C): A ~> C = - { - //System.err.println("append ("+f+","+g+")"); - f match { - case ContOne(ff,nf) => - g match { - case ContOne(fg,ng) if (nf + ng + 1 < MAX_NESTING) => - ContOne({ (tid,depth,a) => - if (depth >= MAX_NESTING - 1) { - Compose(Done(a),ContCons(f,g)) - } else { - val af = try { - ff(tid,depth+1,a) - } catch { - case ex: CallCCThrowable[B] if (ex.tid==tid) => - ex.current - } - if (af.isDone) - fg(tid,depth+1,af.result.get) - else - Compose(af,g) - } - }, - nf + ng + 1) - case ContCons(g1,g2) => - g1 match { - case ContOne(fg1,ng1) if (nf+ng1+1 < MAX_NESTING) => - ContCons(append(f,g1),g2) - case _ => ContCons(f,g) - } - case _ => ContCons(f,g) - } - case ContCons(f1,f2) => ContCons(f1,append(f2,g)) - } - } - - - @inline - def compose[A,B](ca:ComputationBounds[A], - cont:(TrampolineId,Int,A)=>ComputationBounds[B]): ComputationBounds[B] = - ca match { - case Compose(x,xcont) => Compose(x,append(xcont,ContOne(cont))) - case _ => Compose(ca,ContOne(cont)) - } - - - @inline - def compose[A,B](ca:ComputationBounds[A], cont:A=>ComputationBounds[B]): ComputationBounds[B] = - compose(ca,{ (tid:TrampolineId, nesting:Int, x:A) => cont(x)}); - - - - - final val MAX_NESTING=500; - - -} - - diff --git a/src/main/scala/termware/ContextTermOps.scala b/src/main/scala/termware/ContextTermOps.scala new file mode 100644 index 0000000..ca88859 --- /dev/null +++ b/src/main/scala/termware/ContextTermOps.scala @@ -0,0 +1,11 @@ +package termware + +trait ContextTermOps extends TermOps +{ + this: ContextTerm => + + override def name = body.name + + override def cardinality = body.cardinality + +} diff --git a/src/main/scala/termware/DoubleTermOps.scala b/src/main/scala/termware/DoubleTermOps.scala new file mode 100644 index 0000000..0868733 --- /dev/null +++ b/src/main/scala/termware/DoubleTermOps.scala @@ -0,0 +1,10 @@ +package termware + +trait DoubleTermOps extends NumericTermOps +{ + this: DoubleTerm => + + override val name = DoubleName(value) + + +} diff --git a/src/main/scala/termware/EmptySetTermOps.scala b/src/main/scala/termware/EmptySetTermOps.scala new file mode 100644 index 0000000..4ec143f --- /dev/null +++ b/src/main/scala/termware/EmptySetTermOps.scala @@ -0,0 +1,12 @@ +package termware + +trait EmptySetTermOps extends TermOps +{ + + this: EmptySetTerm => + + override def name = SetName + + override def cardinality = TermCardinality.ZERO + +} diff --git a/src/main/scala/termware/ErrorTermOps.scala b/src/main/scala/termware/ErrorTermOps.scala new file mode 100644 index 0000000..4a5fa0f --- /dev/null +++ b/src/main/scala/termware/ErrorTermOps.scala @@ -0,0 +1,10 @@ +package termware + +trait ErrorTermOps extends TermOps +{ + this: ErrorTerm => + + override def name = ErrorName + + override def cardinality = TermCardinality.ERROR +} diff --git a/src/main/scala/termware/Int32TermOps.scala b/src/main/scala/termware/Int32TermOps.scala new file mode 100644 index 0000000..19a3d79 --- /dev/null +++ b/src/main/scala/termware/Int32TermOps.scala @@ -0,0 +1,9 @@ +package termware + +trait Int32TermOps extends NumericTermOps +{ + this: Int32Term => + + override val name = IntName(value) + +} diff --git a/src/main/scala/termware/Int64TermOps.scala b/src/main/scala/termware/Int64TermOps.scala new file mode 100644 index 0000000..b52c772 --- /dev/null +++ b/src/main/scala/termware/Int64TermOps.scala @@ -0,0 +1,9 @@ +package termware + +trait Int64TermOps extends NumericTermOps +{ + this: Int64Term => + + override val name = LongName(value) + +} diff --git a/src/main/scala/termware/Name.scala b/src/main/scala/termware/Name.scala index ca5b07c..5124734 100644 --- a/src/main/scala/termware/Name.scala +++ b/src/main/scala/termware/Name.scala @@ -1,9 +1,136 @@ package termware -sealed trait Name -case class SymbolName(s:Symbol) extends Name -case class PrimitiveName[V](v:V) extends Name +sealed trait Name extends Ordered[Name] +{ + def typeIndex: Int + + def compare(that: Name): Int = + { + val cmp = typeIndex - that.typeIndex + if (cmp !=0) cmp else compareSameTypeIndex(that) + } + + def compareSameTypeIndex(that: Name): Int + +} + +sealed abstract class StringLikeName(val value:String) extends Name +{ + + def compareSameTypeIndex(that: Name) = + value compare that.asInstanceOf[StringLikeName].value + +} + +object NameTypeIndexes +{ + final val ATOM = 1 + final val STRING = 2 + final val LONG = 3 + val INT = 4 + val CHAR = 5 + val DOUBLE = 6 + val OPAQUE = 7 + val SET = 8 + val ARROW = 9 + val UNIVERSUM = 10 + val ERROR = 11 +} + +import NameTypeIndexes._ + +case class AtomName(v:String) extends StringLikeName(v) +{ + def typeIndex = ATOM +} + +case class StringName(v:String) extends StringLikeName(v) +{ + def typeIndex = STRING +} + +sealed abstract class CharLikeName(val value:Char) extends Name +{ + def typeIndex = CHAR + + def compareSameTypeIndex(that: Name) = + value compare that.asInstanceOf[CharLikeName].value +} + +case class CharName(v: Char) extends CharLikeName(v) + +case class LongName(val value:Long) extends Name +{ + + def typeIndex = LONG + + def compareSameTypeIndex(that: Name) = + value compare that.asInstanceOf[LongName].value + +} + +case class IntName(val value:Int) extends Name +{ + + def typeIndex = INT + + def compareSameTypeIndex(that: Name) = + value compare that.asInstanceOf[IntName].value + +} + +case class DoubleName(val value: Double) extends Name +{ + + def typeIndex = DOUBLE + + def compareSameTypeIndex(that: Name) = + value compare that.asInstanceOf[DoubleName].value + +} + +case class OpaqueName(val value: Array[Byte]) extends Name +{ + + def typeIndex = OPAQUE + + def compareSameTypeIndex(that: Name) = + { + val other = that.asInstanceOf[OpaqueName] + var c = value.length - other.value.length + if (c!=0) { + c + } else { + var i=0; + while(c!=0 && i +} diff --git a/src/main/scala/termware/OpaqueTermOps.scala b/src/main/scala/termware/OpaqueTermOps.scala new file mode 100644 index 0000000..b7cf474 --- /dev/null +++ b/src/main/scala/termware/OpaqueTermOps.scala @@ -0,0 +1,9 @@ +package termware + +trait OpaqueTermOps extends PrimitiveTermOps +{ + this: OpaqueTerm => + + override val name = OpaqueName(value) + +} diff --git a/src/main/scala/termware/PrimitiveTerm.scala b/src/main/scala/termware/PrimitiveTerm.scala deleted file mode 100644 index dcf7de1..0000000 --- a/src/main/scala/termware/PrimitiveTerm.scala +++ /dev/null @@ -1,73 +0,0 @@ -package termware - -import scala.reflect.runtime.universe._ -import scala.math._ - - -abstract class PrimitiveToTerm[X:TypeTag] extends ToTerm[X] -{ - - def name(x:X):Name = PrimitiveName[X](x) - - def arity(x:X) = 0 - - def subterms(x:X):IndexedSeq[BaseAsTerm] = IndexedSeq() - - def nameSubterms(x:X):Map[Name,BaseAsTerm] = Map() - - def isAtom(x:X) = false - - def isPrimitive(x:X) = true - - def is[T](x:X)(implicit ttag:TypeTag[T]):Boolean = - (typeOf[T] <:< typeOf[X]) - - def value[T](t:X)(implicit ttag:TypeTag[T]):Option[T] = - if (typeOf[T] <:< typeOf[X]) { - Some(t.asInstanceOf[T]) - } else { - None - } - - def v(x:X):X = x - - -} - -class NumericToTerm[X <% ScalaNumericConversions](implicit xtag:TypeTag[X]) extends PrimitiveToTerm[X] -{ - - override def isNumber(x:X) = true - - override def numberValue(x:X) = Some(x) - -} - -object IntToTerm extends NumericToTerm[Int] - -object LongToTerm extends NumericToTerm[Long] - -object FloatToTerm extends NumericToTerm[Float] - -object DoubleToTerm extends NumericToTerm[Double] - -// bag in compiler ??? -// (now implicit val is instantiated in package object) -//object BigDecimalToTerm extends NumericToTerm[BigDecimal] -// -//object BigIntToTerm extends NumericToTerm[BigInt](typeTag[BigInt]) - -class NonNumericPrimitiveToTerm[X:TypeTag] extends PrimitiveToTerm[X] -{ - - def isNumber(x:X) = false - - def numberValue(x:X) = None - -} - -// -//object StringToTerm extends NonNumericPrimitiveToTerm[String] - - -// vim: set ts=4 sw=4 et: diff --git a/src/main/scala/termware/PrimitiveTermOps.scala b/src/main/scala/termware/PrimitiveTermOps.scala new file mode 100644 index 0000000..ab813a7 --- /dev/null +++ b/src/main/scala/termware/PrimitiveTermOps.scala @@ -0,0 +1,13 @@ +package termware + +trait PrimitiveTermOps extends TermOps +{ + + this: PrimitiveTerm => + + override def cardinality = TermCardinality.ONE + + override def arity: Int = 0 + + +} diff --git a/src/main/scala/termware/SetTermOps.scala b/src/main/scala/termware/SetTermOps.scala new file mode 100644 index 0000000..50be35d --- /dev/null +++ b/src/main/scala/termware/SetTermOps.scala @@ -0,0 +1,11 @@ +package termware + +trait SetTermOps extends TermOps { + + this: SetTerm => + + override def name = SetName + + override def cardinality = TermCardinality.FINITE + +} diff --git a/src/main/scala/termware/StringTermOps.scala b/src/main/scala/termware/StringTermOps.scala new file mode 100644 index 0000000..8ff9729 --- /dev/null +++ b/src/main/scala/termware/StringTermOps.scala @@ -0,0 +1,8 @@ +package termware + +trait StringTermOps extends PrimitiveTermOps +{ + this: StringTerm => + + override val name = StringName(value) +} diff --git a/src/main/scala/termware/StructuredTermOps.scala b/src/main/scala/termware/StructuredTermOps.scala new file mode 100644 index 0000000..473dded --- /dev/null +++ b/src/main/scala/termware/StructuredTermOps.scala @@ -0,0 +1,13 @@ +package termware + +trait StructuredTermOps extends TermOps +{ + this: StructuredTerm => + + override val name = termStructure.name + + override def cardinality: TermCardinality = TermCardinality.ONE + + override def arity: Int = components.length + +} diff --git a/src/main/scala/termware/Term.scala b/src/main/scala/termware/Term.scala index 4b5a771..fb774c5 100644 --- a/src/main/scala/termware/Term.scala +++ b/src/main/scala/termware/Term.scala @@ -1,127 +1,44 @@ package termware -import scala.reflect.runtime.universe._ -import scala.math._ -trait Term -{ - - def name: Name - - def arity: Int - - def subterms:IndexedSeq[Term] - - def subterm(i:Int): Option[Term] = - if (i + + def name: Name + + def cardinality: TermCardinality + +} diff --git a/src/main/scala/termware/TermStructure.scala b/src/main/scala/termware/TermStructure.scala new file mode 100644 index 0000000..2b7d5f0 --- /dev/null +++ b/src/main/scala/termware/TermStructure.scala @@ -0,0 +1,71 @@ +package termware + +import util._ + +/** + * Simple description: what are name of term and names of components. + **/ +sealed trait TermStructure +{ + + def name: Name + + def componentIndex(name:Name): Option[Int] + + def componentName(i: Int): Option[Name] + + def component(i:Int, t: StructuredTerm): Option[Term] = t.components.lift(i) + + def component(n:Name, t:StructuredTerm): Option[Term] = + componentIndex(n).flatMap(component(_,t)) + +} + +/** + * simple term structure which consists just from sequence of names + **/ +case class SimpleTermStructure(name:Name, componentNames: IndexedSeq[Name]) extends TermStructure +{ + + val componentIndexes = componentNames.foldLeft(Map[Name,Int]()){ (s,e) => s.updated(e,s.size+1) } + + override def componentIndex(name:Name): Option[Int] = componentIndexes.get(name) + + override def componentName(i:Int): Option[Name] = + if (i < componentNames.size) { + Some(componentNames(i)) + } else None + + def varIndex(name:Name): Option[Int] = None + +} + +object SimpleTermStructure +{ + val typeIndex = 1 +} + +case class SeqTermStructure(name:Name) extends TermStructure +{ + + override def componentIndex(name:Name): Option[Int] = + name match { + case IntName(v) => Some(v) + case _ => None + } + + override def componentName(i:Int): Option[Name] = Some(IntName(i)) + + def varIndex(name:Name): Option[Int] = None + +} + +object SeqTermStructure +{ + val typeIndex = 2 +} + +object TermStructure +{ + +} diff --git a/src/main/scala/termware/TrampolineId.scala b/src/main/scala/termware/TrampolineId.scala deleted file mode 100644 index 8fa0c54..0000000 --- a/src/main/scala/termware/TrampolineId.scala +++ /dev/null @@ -1,20 +0,0 @@ -package termware; - -import scala.util._ - -class TrampolineId(val x:Long) extends AnyVal - -object TrampolineId -{ - def next: TrampolineId = - { - val threadId = Thread.currentThread.getId - val localId = local.value + 1 - local.value = localId - new TrampolineId((threadId << 16) + localId) - } - - private[this] val local = new DynamicVariable[Int](0) - -} - diff --git a/src/main/scala/termware/UniTermOps.scala b/src/main/scala/termware/UniTermOps.scala new file mode 100644 index 0000000..9faba8f --- /dev/null +++ b/src/main/scala/termware/UniTermOps.scala @@ -0,0 +1,14 @@ +package termware + +trait UniTermOps extends TermOps +{ + + this: UniTerm => + + override def cardinality: TermCardinality = TermCardinality.ONE + + def arity: Int + + def uniTerm(): UniTerm = this + +} diff --git a/src/main/scala/termware/UniversumTermOps.scala b/src/main/scala/termware/UniversumTermOps.scala new file mode 100644 index 0000000..9815a51 --- /dev/null +++ b/src/main/scala/termware/UniversumTermOps.scala @@ -0,0 +1,12 @@ +package termware + +trait UniversumTermOps extends TermOps +{ + + this: UniversumTerm => + + override def name = UniversumName + + override def cardinality = TermCardinality.UNIVERSUM + +} diff --git a/src/main/scala/termware/package.scala b/src/main/scala/termware/package.scala deleted file mode 100644 index 033fa64..0000000 --- a/src/main/scala/termware/package.scala +++ /dev/null @@ -1,21 +0,0 @@ -import language.implicitConversions - -import scala.reflect.runtime.universe._ - - -package object termware { - - - implicit def toTerm[T:TypeTag](x:T)(implicit ops:ToTerm[T]) = new AsTerm(x,ops) - - implicit val intToTerm = IntToTerm - implicit val longToTerm = LongToTerm - implicit val floatToTerm = FloatToTerm - implicit val doubleToTerm = DoubleToTerm - - implicit val bigDecimalToTerm = new NumericToTerm[BigDecimal] - implicit val bigIntToTerm = new NumericToTerm[BigInt] - - implicit val stringToTerm = new NonNumericPrimitiveToTerm[String] - -} diff --git a/src/main/scala/termware/util/Input.scala b/src/main/scala/termware/util/Input.scala new file mode 100644 index 0000000..af8a84a --- /dev/null +++ b/src/main/scala/termware/util/Input.scala @@ -0,0 +1,51 @@ +package termware.util + +import java.nio.charset.StandardCharsets + +trait Input +{ + + def read(bytes: Array[Byte]):Int + + def readByte(): Byte + + def readInt():Int = + { + val v0 = readByte + val v1 = readByte + val v2 = readByte + val v3 = readByte + (((v0 << 8 + v1) << 8) + v2)<<8 + v3 + } + + def readChar():Char = + readInt.toChar + + def readLong(): Long = + { + val v0 = readInt + val v1 = readInt + (v0.toLong << 32) | v1 + } + + def readDouble(): Double = + java.lang.Double.longBitsToDouble(readLong) + + def readString(): String = + { + val bytes = readOpaque + new String(bytes,StandardCharsets.UTF_8) + } + + def readOpaque(): Array[Byte] = + { + val length = readInt + val bytes = new Array[Byte](length) + val n = read(bytes) + if (n> 24).toByte) + write((v >> 16).toByte) + write((v >> 8).toByte ) + write((v ).toByte ) + this + } + + def <<(v:Int): this.type = writeInt(v) + + def writeLong(v:Long): this.type = + { + writeInt( (v>>32).toInt ).writeInt( (v & 0xFFFFFFFF).toInt ) + } + + def <<(v:Long): this.type = writeLong(v) + + def writeString(s: String): this.type = + { + val bytes = s.getBytes(StandardCharsets.UTF_8) + writeInt(bytes.length).write(bytes) + this + } + + def <<(s:String): this.type = writeString(s) + + def writeDouble(v:Double): this.type = + writeLong(java.lang.Double.doubleToLongBits(v)) + + def <<(v:Double): this.type = writeDouble(v) + + def <<(v:Array[Byte]): this.type = { + writeInt(v.length) + write(v) + this + } + +} + + +object Output +{ + + +} diff --git a/src/test/scala/termware/BaseTermFunSuite.scala b/src/test/scala/termware/BaseTermFunSuite.scala deleted file mode 100644 index d2c6628..0000000 --- a/src/test/scala/termware/BaseTermFunSuite.scala +++ /dev/null @@ -1,35 +0,0 @@ -package termware - - -import org.scalatest.FunSuite -import org.scalatest.matchers.ShouldMatchers - -class BaseTermFunSuite extends FunSuite - with ShouldMatchers -{ - - test("int term must exists") { - val t: Term = 5 - t.arity should be(0) - val subterms = 5.subterms - t.is[Int] should be(true) - t.value[Int] should be(Some(5)) - t.isNumber should be(true) - } - - test("long term must exists") { - val t: Term = 5L - t.arity should be(0) - t.is[Long] should be(true) - t.is[Int] should be(false) - t.value[Long] should be(Some(5L)) - t.isNumber should be(true) - t.numberValue.get.intValue() should be(5) - } - - - -} - - -// vim: set ts=4 sw=4 et: diff --git a/src/test/scala/termware/ComputationBoundsFunSuite.scala b/src/test/scala/termware/ComputationBoundsFunSuite.scala deleted file mode 100644 index 034993d..0000000 --- a/src/test/scala/termware/ComputationBoundsFunSuite.scala +++ /dev/null @@ -1,73 +0,0 @@ -package termware - - -import org.scalatest.FunSuite -import org.scalatest.matchers.ShouldMatchers - -class ComputationBoundsFunSuite extends FunSuite - with ShouldMatchers -{ - - test("100000 recursive calls must be handled") { - def f1(n:Int): ComputationBounds[Int] = Call{ (tid,depth) => - //System.err.println("f1(%d), nesting=%s".format(n,depth.toString)); - if (n==0) Done(0) - else if (n>0) { - Call.nested(tid,depth){ (tid, depth) => - //System.err.println("in nested, depth="+depth.toString); - for(x <- f1(n-1)) yield x+n ; - } - } else { - throw new IllegalArgumentException("n must be >0"); - } - } - def f2(n:Int):Int = (1 to n).sum - try { - val x1 = f1(100000).get - val x2 = f2(100000) - x1 should equal(x2) - } catch { - case ex: StackOverflowError => ex.printStackTrace(); - throw new RuntimeException(ex); - } - } - - test("internal rec call must be work") { - def f1(n:Int): ComputationBounds[Int] = Call{ (tid,depth) => - //System.err.println("f1(%d), depth=%d".format(n,depth)); - if (n==0) Done(0) - else if (n>0) { - for(x <- f1(n-1)) yield x+n ; - } else { - throw new IllegalArgumentException("n must be >0"); - } - } - def f2(n:Int):Int = (1 to n).sum - val x1 = f1(100000).get - val x2 = f2(100000) - x1 should equal(x2) - } - - test("inProcess shoud show depth and trampolineId") { - var maxDepth: Int = 0; - def f(n:Int):ComputationBounds[Int] = Call{ (tid, depth) => - //System.err.println("f1(%d), depth=%d".format(n,depth)); - if (n > 1) { - for(x <- f(n-1).inProcess) yield { - (tid,depth) => //System.err.println("tid="+tid+", depth="+depth) - if (n > maxDepth) { - maxDepth = n - } - n + depth - } - } else Done(1) - } - val x = f(10).get - maxDepth should be >(0) - } - - -} - - -// vim: set ts=4 sw=4 et: