mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibJS: Start building a JavaScript engine for SerenityOS :^)
I always tell people to start building things by working on the thing that seems the most interesting right now. The most interesting thing here was an AST + simple interpreter, so that's where we start! There is no lexer or parser yet, we build an AST directly and then execute it in the interpreter, producing a return value. This seems like the start of something interesting. :^)
This commit is contained in:
parent
f2f16e1c24
commit
f5476be702
Notes:
sideshowbarker
2024-07-19 08:51:14 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/f5476be7020
14 changed files with 957 additions and 1 deletions
144
Libraries/LibJS/AST.cpp
Normal file
144
Libraries/LibJS/AST.cpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Function.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Value.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
Value ScopeNode::execute(Interpreter& interpreter) const
|
||||
{
|
||||
return interpreter.run(*this);
|
||||
}
|
||||
|
||||
Value FunctionDeclaration::execute(Interpreter& interpreter) const
|
||||
{
|
||||
auto* function = new Function(name(), body());
|
||||
interpreter.global_object().put(m_name, Value(function));
|
||||
return Value(function);
|
||||
}
|
||||
|
||||
Value CallExpression::execute(Interpreter& interpreter) const
|
||||
{
|
||||
auto callee = interpreter.global_object().get(name());
|
||||
ASSERT(callee.is_object());
|
||||
auto* callee_object = callee.as_object();
|
||||
ASSERT(callee_object->is_function());
|
||||
auto& function = static_cast<Function&>(*callee_object);
|
||||
return interpreter.run(function.body());
|
||||
}
|
||||
|
||||
Value ReturnStatement::execute(Interpreter& interpreter) const
|
||||
{
|
||||
auto value = argument().execute(interpreter);
|
||||
interpreter.do_return();
|
||||
return value;
|
||||
}
|
||||
|
||||
Value add(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value(lhs.as_double() + rhs.as_double());
|
||||
}
|
||||
|
||||
Value sub(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value(lhs.as_double() - rhs.as_double());
|
||||
}
|
||||
|
||||
Value BinaryExpression::execute(Interpreter& interpreter) const
|
||||
{
|
||||
auto lhs_result = m_lhs->execute(interpreter);
|
||||
auto rhs_result = m_rhs->execute(interpreter);
|
||||
|
||||
switch (m_op) {
|
||||
case BinaryOp::Plus:
|
||||
return add(lhs_result, rhs_result);
|
||||
case BinaryOp::Minus:
|
||||
return sub(lhs_result, rhs_result);
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
static void print_indent(int indent)
|
||||
{
|
||||
for (int i = 0; i < indent * 2; ++i)
|
||||
putchar(' ');
|
||||
}
|
||||
|
||||
void ASTNode::dump(int indent) const
|
||||
{
|
||||
print_indent(indent);
|
||||
printf("%s\n", class_name());
|
||||
}
|
||||
|
||||
void ScopeNode::dump(int indent) const
|
||||
{
|
||||
ASTNode::dump(indent);
|
||||
for (auto& child : children())
|
||||
child.dump(indent + 1);
|
||||
}
|
||||
|
||||
void BinaryExpression::dump(int indent) const
|
||||
{
|
||||
ASTNode::dump(indent);
|
||||
m_lhs->dump(indent + 1);
|
||||
m_rhs->dump(indent + 1);
|
||||
}
|
||||
|
||||
void CallExpression::dump(int indent) const
|
||||
{
|
||||
print_indent(indent);
|
||||
printf("%s '%s'\n", class_name(), name().characters());
|
||||
}
|
||||
|
||||
void Literal::dump(int indent) const
|
||||
{
|
||||
print_indent(indent);
|
||||
printf("%d\n", (i32)m_value.as_double());
|
||||
}
|
||||
|
||||
void FunctionDeclaration::dump(int indent) const
|
||||
{
|
||||
print_indent(indent);
|
||||
printf("%s '%s'\n", class_name(), name().characters());
|
||||
body().dump(indent + 1);
|
||||
}
|
||||
|
||||
void ReturnStatement::dump(int indent) const
|
||||
{
|
||||
ASTNode::dump(indent);
|
||||
argument().dump(indent + 1);
|
||||
}
|
||||
|
||||
}
|
188
Libraries/LibJS/AST.h
Normal file
188
Libraries/LibJS/AST.h
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullOwnPtrVector.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class ASTNode {
|
||||
public:
|
||||
virtual ~ASTNode() {}
|
||||
virtual const char* class_name() const = 0;
|
||||
virtual Value execute(Interpreter&) const = 0;
|
||||
virtual void dump(int indent) const;
|
||||
|
||||
protected:
|
||||
ASTNode() {}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class ScopeNode : public ASTNode {
|
||||
public:
|
||||
template<typename T, typename... Args>
|
||||
T& append(Args&&... args)
|
||||
{
|
||||
auto child = make<T>(forward<Args>(args)...);
|
||||
m_children.append(move(child));
|
||||
return static_cast<T&>(m_children.last());
|
||||
}
|
||||
|
||||
const NonnullOwnPtrVector<ASTNode>& children() const { return m_children; }
|
||||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
|
||||
protected:
|
||||
ScopeNode() {}
|
||||
|
||||
private:
|
||||
NonnullOwnPtrVector<ASTNode> m_children;
|
||||
};
|
||||
|
||||
class Program : public ScopeNode {
|
||||
public:
|
||||
Program() {}
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "Program"; }
|
||||
};
|
||||
|
||||
class BlockStatement : public ScopeNode {
|
||||
public:
|
||||
BlockStatement() {}
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "BlockStatement"; }
|
||||
};
|
||||
|
||||
class FunctionDeclaration : public ASTNode {
|
||||
public:
|
||||
FunctionDeclaration(String name, NonnullOwnPtr<ScopeNode> body)
|
||||
: m_name(move(name))
|
||||
, m_body(move(body))
|
||||
{
|
||||
}
|
||||
|
||||
String name() const { return m_name; }
|
||||
const ScopeNode& body() const { return *m_body; }
|
||||
|
||||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "FunctionDeclaration"; }
|
||||
|
||||
String m_name;
|
||||
NonnullOwnPtr<ScopeNode> m_body;
|
||||
};
|
||||
|
||||
class Expression : public ASTNode {
|
||||
public:
|
||||
};
|
||||
|
||||
class ReturnStatement : public ASTNode {
|
||||
public:
|
||||
explicit ReturnStatement(NonnullOwnPtr<Expression> argument)
|
||||
: m_argument(move(argument))
|
||||
{
|
||||
}
|
||||
|
||||
const Expression& argument() const { return *m_argument; }
|
||||
|
||||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "ReturnStatement"; }
|
||||
|
||||
NonnullOwnPtr<Expression> m_argument;
|
||||
};
|
||||
|
||||
enum class BinaryOp {
|
||||
Plus,
|
||||
Minus,
|
||||
};
|
||||
|
||||
class BinaryExpression : public Expression {
|
||||
public:
|
||||
BinaryExpression(BinaryOp op, NonnullOwnPtr<Expression> lhs, NonnullOwnPtr<Expression> rhs)
|
||||
: m_op(op)
|
||||
, m_lhs(move(lhs))
|
||||
, m_rhs(move(rhs))
|
||||
{
|
||||
}
|
||||
|
||||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "BinaryExpression"; }
|
||||
|
||||
BinaryOp m_op;
|
||||
NonnullOwnPtr<Expression> m_lhs;
|
||||
NonnullOwnPtr<Expression> m_rhs;
|
||||
};
|
||||
|
||||
class Literal : public Expression {
|
||||
public:
|
||||
explicit Literal(Value value)
|
||||
: m_value(move(value))
|
||||
{
|
||||
}
|
||||
|
||||
virtual Value execute(Interpreter&) const override { return m_value; }
|
||||
virtual void dump(int indent) const override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "Literal"; }
|
||||
|
||||
Value m_value;
|
||||
};
|
||||
|
||||
class CallExpression : public Expression {
|
||||
public:
|
||||
explicit CallExpression(String name)
|
||||
: m_name(move(name))
|
||||
{
|
||||
}
|
||||
|
||||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
|
||||
const String& name() const { return m_name; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "CallExpression"; }
|
||||
|
||||
String m_name;
|
||||
};
|
||||
|
||||
}
|
37
Libraries/LibJS/Forward.h
Normal file
37
Libraries/LibJS/Forward.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace JS {
|
||||
|
||||
class ASTNode;
|
||||
class Interpreter;
|
||||
class Object;
|
||||
class ScopeNode;
|
||||
class Value;
|
||||
|
||||
}
|
42
Libraries/LibJS/Function.cpp
Normal file
42
Libraries/LibJS/Function.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibJS/Function.h>
|
||||
#include <LibJS/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
Function::Function(String name, const ScopeNode& body)
|
||||
: m_name(move(name))
|
||||
, m_body(body)
|
||||
{
|
||||
}
|
||||
|
||||
Function::~Function()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
52
Libraries/LibJS/Function.h
Normal file
52
Libraries/LibJS/Function.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Object.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class Function : public Object {
|
||||
public:
|
||||
Function(String name, const ScopeNode& body);
|
||||
virtual ~Function();
|
||||
|
||||
const String& name() const { return m_name; }
|
||||
const ScopeNode& body() const { return m_body; }
|
||||
|
||||
protected:
|
||||
virtual const char* class_name() const override { return "Function"; }
|
||||
|
||||
private:
|
||||
virtual bool is_function() const final { return true; }
|
||||
|
||||
String m_name;
|
||||
const ScopeNode& m_body;
|
||||
};
|
||||
|
||||
}
|
72
Libraries/LibJS/Interpreter.cpp
Normal file
72
Libraries/LibJS/Interpreter.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Object.h>
|
||||
#include <LibJS/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
Interpreter::Interpreter()
|
||||
{
|
||||
m_global_object = new Object;
|
||||
}
|
||||
|
||||
Interpreter::~Interpreter()
|
||||
{
|
||||
}
|
||||
|
||||
Value Interpreter::run(const ScopeNode& scope_node)
|
||||
{
|
||||
enter_scope(scope_node);
|
||||
|
||||
Value last_value = js_undefined();
|
||||
for (auto& node : scope_node.children()) {
|
||||
last_value = node.execute(*this);
|
||||
}
|
||||
|
||||
exit_scope(scope_node);
|
||||
return last_value;
|
||||
}
|
||||
|
||||
void Interpreter::enter_scope(const ScopeNode& scope_node)
|
||||
{
|
||||
m_scope_stack.append({ scope_node });
|
||||
}
|
||||
|
||||
void Interpreter::exit_scope(const ScopeNode& scope_node)
|
||||
{
|
||||
ASSERT(&m_scope_stack.last().scope_node == &scope_node);
|
||||
m_scope_stack.take_last();
|
||||
}
|
||||
|
||||
void Interpreter::do_return()
|
||||
{
|
||||
dbg() << "FIXME: Implement Interpreter::do_return()";
|
||||
}
|
||||
|
||||
}
|
59
Libraries/LibJS/Interpreter.h
Normal file
59
Libraries/LibJS/Interpreter.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
struct ScopeFrame {
|
||||
const ScopeNode& scope_node;
|
||||
};
|
||||
|
||||
class Interpreter {
|
||||
public:
|
||||
Interpreter();
|
||||
~Interpreter();
|
||||
|
||||
Value run(const ScopeNode&);
|
||||
|
||||
Object& global_object() { return *m_global_object; }
|
||||
const Object& global_object() const { return *m_global_object; }
|
||||
|
||||
void do_return();
|
||||
|
||||
private:
|
||||
void enter_scope(const ScopeNode&);
|
||||
void exit_scope(const ScopeNode&);
|
||||
|
||||
Vector<ScopeFrame> m_scope_stack;
|
||||
|
||||
Object* m_global_object { nullptr };
|
||||
};
|
||||
|
||||
}
|
15
Libraries/LibJS/Makefile
Normal file
15
Libraries/LibJS/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
OBJS = \
|
||||
AST.o \
|
||||
Function.o \
|
||||
Interpreter.o \
|
||||
Object.o \
|
||||
Value.o
|
||||
|
||||
LIBRARY = libjs.a
|
||||
|
||||
install:
|
||||
mkdir -p $(SERENITY_BASE_DIR)/Root/usr/include/LibJS/
|
||||
cp *.h $(SERENITY_BASE_DIR)/Root/usr/include/LibJS/
|
||||
cp $(LIBRARY) $(SERENITY_BASE_DIR)/Root/usr/lib/
|
||||
|
||||
include ../../Makefile.common
|
43
Libraries/LibJS/Object.cpp
Normal file
43
Libraries/LibJS/Object.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Object.h>
|
||||
#include <LibJS/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
Value Object::get(String property_name) const
|
||||
{
|
||||
return m_properties.get(property_name).value_or(js_undefined());
|
||||
}
|
||||
|
||||
void Object::put(String property_name, Value value)
|
||||
{
|
||||
m_properties.set(property_name, move(value));
|
||||
}
|
||||
|
||||
}
|
50
Libraries/LibJS/Object.h
Normal file
50
Libraries/LibJS/Object.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class Object {
|
||||
public:
|
||||
Object() {}
|
||||
virtual ~Object() {}
|
||||
|
||||
Value get(String property_name) const;
|
||||
void put(String property_name, Value);
|
||||
|
||||
virtual bool is_function() const { return false; }
|
||||
|
||||
virtual const char* class_name() const { return "Object"; }
|
||||
|
||||
private:
|
||||
HashMap<String, Value> m_properties;
|
||||
};
|
||||
|
||||
}
|
56
Libraries/LibJS/Value.cpp
Normal file
56
Libraries/LibJS/Value.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Object.h>
|
||||
#include <LibJS/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
String Value::to_string() const
|
||||
{
|
||||
if (is_boolean())
|
||||
return as_bool() ? "true" : "false";
|
||||
|
||||
if (is_null())
|
||||
return "null";
|
||||
|
||||
if (is_undefined())
|
||||
return "null";
|
||||
|
||||
if (is_number()) {
|
||||
// FIXME: This needs improvement.
|
||||
return String::number((i32)as_double());
|
||||
}
|
||||
|
||||
if (is_object()) {
|
||||
return String::format("{%s}", as_object()->class_name());
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
139
Libraries/LibJS/Value.h
Normal file
139
Libraries/LibJS/Value.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/LogStream.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class Value {
|
||||
public:
|
||||
enum class Type {
|
||||
Undefined,
|
||||
Null,
|
||||
Number,
|
||||
String,
|
||||
Object,
|
||||
Boolean,
|
||||
};
|
||||
|
||||
bool is_undefined() const { return m_type == Type::Undefined; }
|
||||
bool is_null() const { return m_type == Type::Null; }
|
||||
bool is_number() const { return m_type == Type::Number; }
|
||||
bool is_string() const { return m_type == Type::String; }
|
||||
bool is_object() const { return m_type == Type::Object; }
|
||||
bool is_boolean() const { return m_type == Type::Boolean; }
|
||||
|
||||
explicit Value(double value)
|
||||
: m_type(Type::Number)
|
||||
{
|
||||
m_value.as_double = value;
|
||||
}
|
||||
|
||||
explicit Value(i32 value)
|
||||
: m_type(Type::Number)
|
||||
{
|
||||
m_value.as_double = value;
|
||||
}
|
||||
|
||||
explicit Value(Object* object)
|
||||
: m_type(Type::Object)
|
||||
{
|
||||
m_value.as_object = object;
|
||||
}
|
||||
|
||||
explicit Value(Type type)
|
||||
: m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
Type type() const { return m_type; }
|
||||
|
||||
double as_double() const
|
||||
{
|
||||
ASSERT(type() == Type::Number);
|
||||
return m_value.as_double;
|
||||
}
|
||||
|
||||
bool as_bool() const
|
||||
{
|
||||
ASSERT(type() == Type::Boolean);
|
||||
return m_value.as_bool;
|
||||
}
|
||||
|
||||
Object* as_object()
|
||||
{
|
||||
ASSERT(type() == Type::Object);
|
||||
return m_value.as_object;
|
||||
}
|
||||
|
||||
const Object* as_object() const
|
||||
{
|
||||
ASSERT(type() == Type::Object);
|
||||
return m_value.as_object;
|
||||
}
|
||||
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Type m_type { Type::Undefined };
|
||||
|
||||
union {
|
||||
bool as_bool;
|
||||
double as_double;
|
||||
StringImpl* as_string;
|
||||
Object* as_object;
|
||||
} m_value;
|
||||
};
|
||||
|
||||
inline Value js_undefined()
|
||||
{
|
||||
return Value(Value::Type::Undefined);
|
||||
}
|
||||
|
||||
inline Value js_null()
|
||||
{
|
||||
return Value(Value::Type::Null);
|
||||
}
|
||||
|
||||
inline const LogStream& operator<<(const LogStream& stream, const Value& value)
|
||||
{
|
||||
switch (value.type()) {
|
||||
case Value::Type::Boolean:
|
||||
return stream << value.as_bool();
|
||||
case Value::Type::Number:
|
||||
return stream << (i32)value.as_double();
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -4,7 +4,7 @@ APPS = ${SRCS:.cpp=}
|
|||
|
||||
EXTRA_CLEAN = $(APPS)
|
||||
|
||||
LIB_DEPS = Web GUI Gfx Audio Protocol IPC Thread Pthread Core PCIDB Markdown
|
||||
LIB_DEPS = Web GUI Gfx Audio Protocol IPC Thread Pthread Core PCIDB Markdown JS
|
||||
|
||||
include ../Makefile.common
|
||||
|
||||
|
|
59
Userland/js.cpp
Normal file
59
Userland/js.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Object.h>
|
||||
#include <LibJS/Value.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
auto program = make<JS::Program>();
|
||||
|
||||
auto block = make<JS::BlockStatement>();
|
||||
block->append<JS::ReturnStatement>(
|
||||
make<JS::BinaryExpression>(
|
||||
JS::BinaryOp::Plus,
|
||||
make<JS::BinaryExpression>(
|
||||
JS::BinaryOp::Plus,
|
||||
make<JS::Literal>(JS::Value(1)),
|
||||
make<JS::Literal>(JS::Value(2))),
|
||||
make<JS::Literal>(JS::Value(3))));
|
||||
|
||||
program->append<JS::FunctionDeclaration>("foo", move(block));
|
||||
program->append<JS::CallExpression>("foo");
|
||||
|
||||
program->dump(0);
|
||||
|
||||
JS::Interpreter interpreter;
|
||||
auto result = interpreter.run(*program);
|
||||
dbg() << "Interpreter returned " << result;
|
||||
|
||||
printf("%s\n", result.to_string().characters());
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue