Files
2026-02-02 04:50:13 +01:00

275 lines
7.6 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "common/util.h"
#include "./ast.h"
#include "./handler.h"
#include "./names.h"
#include "./script.h"
namespace LingoDec {
/* Datum */
int Datum::toInt() {
switch (type) {
case kDatumInt:
return i;
case kDatumFloat:
return f;
default:
break;
}
return 0;
}
/* AST */
void AST::addStatement(Common::SharedPtr<Node> statement) {
currentBlock->addChild(Common::move(statement));
}
void AST::enterBlock(BlockNode *block) {
currentBlock = block;
}
void AST::exitBlock() {
auto ancestorStatement = currentBlock->ancestorStatement();
if (!ancestorStatement) {
currentBlock = nullptr;
return;
}
ancestorStatement->_endOffset = currentBlock->_endOffset;
auto block = ancestorStatement->parent;
if (!block || block->type != kBlockNode) {
currentBlock = nullptr;
return;
}
currentBlock = static_cast<BlockNode *>(block);
}
/* Node */
Common::SharedPtr<Datum> Node::getValue() {
return Common::SharedPtr<Datum>(new Datum());
}
Node *Node::ancestorStatement() {
Node *ancestor = parent;
while (ancestor && !ancestor->isStatement) {
ancestor = ancestor->parent;
}
return ancestor;
}
LoopNode *Node::ancestorLoop() {
Node *ancestor = parent;
while (ancestor && !ancestor->isLoop) {
ancestor = ancestor->parent;
}
return static_cast<LoopNode *>(ancestor);
}
bool Node::hasSpaces(bool) {
return true;
}
/* ErrorNode */
bool ErrorNode::hasSpaces(bool) {
return false;
}
/* LiteralNode */
Common::SharedPtr<Datum> LiteralNode::getValue() {
return value;
}
bool LiteralNode::hasSpaces(bool) {
return false;
}
/* BlockNode */
void BlockNode::addChild(Common::SharedPtr<Node> child) {
child->parent = this;
children.push_back(Common::move(child));
}
/* BinaryOpNode */
unsigned int BinaryOpNode::getPrecedence() const {
switch (opcode) {
case kOpMul:
case kOpDiv:
case kOpMod:
return 1;
case kOpAdd:
case kOpSub:
return 2;
case kOpLt:
case kOpLtEq:
case kOpNtEq:
case kOpEq:
case kOpGt:
case kOpGtEq:
return 3;
case kOpAnd:
return 4;
case kOpOr:
return 5;
default:
break;
}
return 0;
}
/* MemberExprNode */
bool MemberExprNode::hasSpaces(bool dot) {
return !dot;
}
/* VarNode */
bool VarNode::hasSpaces(bool) {
return false;
}
/* CaseStmtNode */
void CaseStmtNode::addOtherwise(uint32 offset) {
otherwise = Common::SharedPtr<OtherwiseNode>(new OtherwiseNode(offset));
otherwise->parent = this;
otherwise->block->endPos = endPos;
}
/* CallNode */
bool CallNode::noParens() const {
if (isStatement) {
// TODO: Make a complete list of commonly paren-less commands
if (name == "put")
return true;
if (name == "return")
return true;
}
return false;
}
bool CallNode::isMemberExpr() const {
if (isExpression) {
size_t nargs = argList->getValue()->l.size();
if (name == "cast" && (nargs == 1 || nargs == 2))
return true;
if (name == "member" && (nargs == 1 || nargs == 2))
return true;
if (name == "script" && (nargs == 1 || nargs == 2))
return true;
if (name == "castLib" && nargs == 1)
return true;
if (name == "window" && nargs == 1)
return true;
}
return false;
}
bool CallNode::hasSpaces(bool dot) {
if (!dot && isMemberExpr())
return true;
if (noParens())
return true;
return false;
}
/* ObjCallNode */
bool ObjCallNode::hasSpaces(bool) {
return false;
}
/* ObjCallV4Node */
bool ObjCallV4Node::hasSpaces(bool) {
return false;
}
/* ObjPropExprNode */
bool ObjPropExprNode::hasSpaces(bool dot) {
return !dot;
}
/* ObjBracketExprNode */
bool ObjBracketExprNode::hasSpaces(bool) {
return false;
}
/* ObjPropIndexExprNode */
bool ObjPropIndexExprNode::hasSpaces(bool) {
return false;
}
void ErrorNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void CommentNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void LiteralNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void IfStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void NewObjNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void EndCaseNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void HandlerNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ObjCallNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void PutStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void TheExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void BinaryOpNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void CaseStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ExitStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void TellStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void WhenStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void CaseLabelNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ChunkExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void InverseOpNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ObjCallV4Node::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void OtherwiseNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void MemberExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ObjPropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void PlayCmdStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ThePropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void MenuPropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void SoundCmdStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void SoundPropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void AssignmentStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ExitRepeatStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void NextRepeatStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ObjBracketExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void SpritePropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ChunkDeleteStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ChunkHiliteStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void RepeatWhileStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void MenuItemPropExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void ObjPropIndexExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void RepeatWithInStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void RepeatWithToStmtNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void SpriteWithinExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void LastStringChunkExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void SpriteIntersectsExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void StringChunkCountExprNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void VarNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void CallNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void BlockNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
void NotOpNode::accept(NodeVisitor &visitor) const { visitor.visit(*this); }
} // namespace LingoDec