Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/compile/special_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ func (g *Generator) emitClassStatementInit(n *node.ClassStatement) error {
if err := g.emitClassAnnotation(ann); err != nil {
return err
}
g.printf(")\n")
g.printf(", nil)\n")
}
return nil
}
Expand Down Expand Up @@ -1027,7 +1027,7 @@ func (g *Generator) emitClassMethod(method data.Method) error {
if err := g.emitClassAnnotation(ann); err != nil {
return err
}
g.printf(")\n")
g.printf(", nil)\n")
}
g.printf("return m\n")
g.indent--
Expand Down
90 changes: 3 additions & 87 deletions node/annotation.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package node

import (
"fmt"

"github.com/php-any/origami/data"
)

Expand Down Expand Up @@ -107,92 +105,10 @@ func (a *Annotation) GetValue(ctx data.Context) (data.GetValue, data.Control) {

if object, ok := object.(*data.ClassValue); ok {
if method := object.Class.GetConstruct(); method != nil {
varies := method.GetVariables()
params := method.GetParams()
fnCtx := object.CreateContext(varies)
// 入参的值设置到上下文中
for index, arg := range a.Arguments {
switch argTV := arg.(type) {
case *NamedArgument:
tempV, acl := argTV.GetValue(ctx)
if acl != nil {
return nil, acl
}
vari, err := findVariable(varies, argTV.Name)
if err != nil {
return nil, data.NewErrorThrow(a.from, err)
}
fnCtx.SetVariableValue(vari, tempV.(data.Value))
default:
tempV, acl := argTV.GetValue(ctx)
if acl != nil {
return nil, acl
}

if index >= len(varies) {
return nil, data.NewErrorThrow(a.from, fmt.Errorf("注解(%v)构造函数参数数量超出限制: %d", a.Name, index))
}

fnCtx.SetVariableValue(varies[index], tempV.(data.Value))
}
}

// 处理未传递的参数,设置默认值
for index := len(a.Arguments); index < len(params); index++ {
if index >= len(varies) {
break
}
param := params[index]
if targetParam := asAnnotationTargetParam(param); targetParam != nil {
// 将被注解的 AST 目标按需注入构造函数
// 注意:a.Target 类型是 data.GetValue,直接塞进 any 会二次装箱导致
// anyT.Value.(*ClassStatement) 失败,需先解开具体类型。
fnCtx.SetVariableValue(targetParam, data.NewAnyValue(unwrapAnnotationTarget(a.Target)))
continue
}
if argObj, ok := param.(*Parameter); ok {
if argObj.DefaultValue == nil {
return nil, data.NewErrorThrow(a.from, fmt.Errorf("调用 %s 构造函数时参数 %s 缺少值和默认值", a.Name, argObj.Name))
}
// 调用 GetValue 来触发默认值的设置
_, acl := argObj.GetValue(fnCtx)
if acl != nil {
return nil, acl
}
}
fnCtx, acl := bindAnnotationConstructorArgs(a, ctx, object)
if acl != nil {
return nil, acl
}

// 将构造函数参数属性的值赋值给对象属性(PHP 8 构造函数参数属性提升)
for index, param := range params {
// 检查是否是属性提升的参数
if promotedParam, ok := param.(*PromotedParameter); ok {
// 从函数上下文获取参数值
if index < len(varies) {
paramValue, acl := fnCtx.GetVariableValue(varies[index])
if acl != nil {
// 如果获取失败,尝试使用默认值
if promotedParam.DefaultValue != nil {
paramValueGet, acl := promotedParam.DefaultValue.GetValue(fnCtx)
if acl != nil {
return nil, acl
}
if paramValueGet != nil {
paramValue = paramValueGet.(data.Value)
}
} else {
// 没有默认值,跳过
continue
}
}
// 将参数值赋值给对象属性
if paramValue != nil {
object.SetProperty(promotedParam.PropertyName, paramValue)
}
}
}
}

// 构造函数执行成功后,返回注解实例本身
return object, &CallAnn{method: method, ctx: fnCtx}
}
}
Expand Down
121 changes: 121 additions & 0 deletions node/annotation_reflection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package node

import (
"fmt"

"github.com/php-any/origami/data"
)

// ClassStmtHasAnnotationTargetParameter 注解构造函数是否包含编译器注入的 target 形参。
func ClassStmtHasAnnotationTargetParameter(stmt data.ClassStmt) bool {
if stmt == nil {
return false
}
construct := stmt.GetConstruct()
if construct == nil {
return false
}
for _, param := range construct.GetParams() {
if asAnnotationTargetParam(param) != nil {
return true
}
}
return false
}

// InstantiateAnnotationForReflection 按注解声明绑定用户实参与 target,但不执行构造副作用(无 InitAnnotation)。
func InstantiateAnnotationForReflection(a *Annotation, ctx data.Context) (data.GetValue, data.Control) {
stmt, acl := a.resolveClass(ctx)
if acl != nil {
return nil, acl
}
object, acl := stmt.GetValue(ctx.CreateBaseContext())
if acl != nil {
return nil, acl
}
cv, ok := object.(*data.ClassValue)
if !ok || cv.Class.GetConstruct() == nil {
return object, nil
}
if _, acl := bindAnnotationConstructorArgs(a, ctx, cv); acl != nil {
return nil, acl
}
return cv, nil
}

// bindAnnotationConstructorArgs 将声明中的用户实参与 target 绑定到构造上下文(不调用 __construct)。
func bindAnnotationConstructorArgs(a *Annotation, ctx data.Context, object *data.ClassValue) (data.Context, data.Control) {
method := object.Class.GetConstruct()
varies := method.GetVariables()
params := method.GetParams()
fnCtx := object.CreateContext(varies)

for index, arg := range a.Arguments {
switch argTV := arg.(type) {
case *NamedArgument:
tempV, acl := argTV.GetValue(ctx)
if acl != nil {
return nil, acl
}
vari, err := findVariable(varies, argTV.Name)
if err != nil {
return nil, data.NewErrorThrow(a.from, err)
}
fnCtx.SetVariableValue(vari, tempV.(data.Value))
default:
tempV, acl := argTV.GetValue(ctx)
if acl != nil {
return nil, acl
}
if index >= len(varies) {
return nil, data.NewErrorThrow(a.from, fmt.Errorf("注解(%v)构造函数参数数量超出限制: %d", a.Name, index))
}
fnCtx.SetVariableValue(varies[index], tempV.(data.Value))
}
}

for index := len(a.Arguments); index < len(params); index++ {
if index >= len(varies) {
break
}
param := params[index]
if targetParam := asAnnotationTargetParam(param); targetParam != nil {
fnCtx.SetVariableValue(targetParam, data.NewAnyValue(unwrapAnnotationTarget(a.Target)))
continue
}
if argObj, ok := param.(*Parameter); ok {
if argObj.DefaultValue == nil {
return nil, data.NewErrorThrow(a.from, fmt.Errorf("调用 %s 构造函数时参数 %s 缺少值和默认值", a.Name, argObj.Name))
}
_, acl := argObj.GetValue(fnCtx)
if acl != nil {
return nil, acl
}
}
}

for index, param := range params {
if promotedParam, ok := param.(*PromotedParameter); ok {
if index < len(varies) {
paramValue, acl := fnCtx.GetVariableValue(varies[index])
if acl != nil {
if promotedParam.DefaultValue != nil {
paramValueGet, acl := promotedParam.DefaultValue.GetValue(fnCtx)
if acl != nil {
return nil, acl
}
if paramValueGet != nil {
paramValue = paramValueGet.(data.Value)
}
} else {
continue
}
}
if paramValue != nil {
object.SetProperty(promotedParam.PropertyName, paramValue)
}
}
}
}
return fnCtx, nil
}
27 changes: 22 additions & 5 deletions node/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type ClassStatement struct {
initialization atomic.Pointer[classInitialization]
privateLookup atomic.Pointer[privateMethodIndex]
Annotations []*data.ClassValue // 类注解列表
AnnotationDecls []*Annotation // 与 Annotations 下标对应的源码声明

// 构造函数
Construct data.Method
Expand Down Expand Up @@ -289,11 +290,13 @@ func (c *ClassStatement) GetImplements() []string {
return c.Implements
}

func (c *ClassStatement) AddAnnotations(a *data.ClassValue) {
func (c *ClassStatement) AddAnnotations(a *data.ClassValue, decl *Annotation) {
if c.Annotations == nil {
c.Annotations = []*data.ClassValue{}
c.AnnotationDecls = []*Annotation{}
}
c.Annotations = append(c.Annotations, a)
c.AnnotationDecls = append(c.AnnotationDecls, decl)
}

func (c *ClassStatement) GetPropertyList() []data.Property {
Expand Down Expand Up @@ -572,7 +575,8 @@ type ClassProperty struct {
Virtual bool
IsPromoted bool // 是否是构造函数参数属性提升
DefaultValue data.GetValue // 默认值
Annotations []*data.ClassValue // 属性注解列表
Annotations []*data.ClassValue // 属性注解列表
AnnotationDecls []*Annotation // 与 Annotations 下标对应的源码声明
Type data.TypeRef // 属性类型
IsConstant bool
DeclaringClass string
Expand Down Expand Up @@ -744,11 +748,13 @@ func (p *ClassProperty) GetIsStatic() bool {
return p.IsStatic
}

func (p *ClassProperty) AddAnnotations(a *data.ClassValue) {
func (p *ClassProperty) AddAnnotations(a *data.ClassValue, decl *Annotation) {
if p.Annotations == nil {
p.Annotations = []*data.ClassValue{}
p.AnnotationDecls = []*Annotation{}
}
p.Annotations = append(p.Annotations, a)
p.AnnotationDecls = append(p.AnnotationDecls, decl)
}

type ClassMethod struct {
Expand All @@ -760,6 +766,7 @@ type ClassMethod struct {
Body []data.GetValue // 方法体
vars []data.Variable
Annotations []*data.ClassValue // 方法注解列表
AnnotationDecls []*Annotation // 与 Annotations 下标对应的源码声明
Ret data.TypeRef // 返回类型
IsGenerator bool // 是否是生成器方法(含 yield)
StrictTypes bool
Expand Down Expand Up @@ -791,11 +798,13 @@ func NewMethod(from data.From, name string, modifier string, isStatic bool, para
}
}

func (m *ClassMethod) AddAnnotations(a *data.ClassValue) {
func (m *ClassMethod) AddAnnotations(a *data.ClassValue, decl *Annotation) {
if m.Annotations == nil {
m.Annotations = []*data.ClassValue{}
m.AnnotationDecls = []*Annotation{}
}
m.Annotations = append(m.Annotations, a)
m.AnnotationDecls = append(m.AnnotationDecls, decl)
}

func (m *ClassMethod) GetIsStatic() bool {
Expand Down Expand Up @@ -937,5 +946,13 @@ func checkClassIs(ctx data.Context, source data.ClassStmt, target string) (bool,
}

type AddAnnotations interface {
AddAnnotations(a *data.ClassValue)
AddAnnotations(a *data.ClassValue, decl *Annotation)
}

// AnnotationDeclAt 返回与已应用注解实例同下标的源码声明(可能为 nil)。
func AnnotationDeclAt(decls []*Annotation, index int) *Annotation {
if index < 0 || index >= len(decls) {
return nil
}
return decls[index]
}
4 changes: 2 additions & 2 deletions node/class_abstract.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ func (c *AbstractClassStatement) GetValue(ctx data.Context) (data.GetValue, data
}

// AddAnnotations 添加注解(实现 AddAnnotations 接口)
func (c *AbstractClassStatement) AddAnnotations(a *data.ClassValue) {
c.ClassStatement.AddAnnotations(a)
func (c *AbstractClassStatement) AddAnnotations(a *data.ClassValue, decl *Annotation) {
c.ClassStatement.AddAnnotations(a, decl)
}
3 changes: 2 additions & 1 deletion node/class_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ func CloneClassDeclaration(source data.ClassStmt) data.ClassStmt {
Methods: maps.Clone(core.Methods), StaticMethods: maps.Clone(core.StaticMethods),
Construct: core.Construct, IsAbstract: core.IsAbstract, Flags: core.Flags,
EnumCases: slices.Clone(core.EnumCases),
Annotations: slices.Clone(core.Annotations),
Annotations: slices.Clone(core.Annotations),
AnnotationDecls: slices.Clone(core.AnnotationDecls),
Traits: slices.Clone(core.Traits), DeferredTraits: slices.Clone(core.DeferredTraits),
DeferredTraitAliases: slices.Clone(core.DeferredTraitAliases),
DeferredTraitsMerged: core.DeferredTraitsMerged,
Expand Down
6 changes: 3 additions & 3 deletions node/class_register.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ func classStmtFromAny(v data.ClassStmt) *ClassStatement {
}

// AddAnnotations 转发到内部 ClassStatement(AnnotationParser 以 ClassRegisterStmt 为 next)
func (s *ClassRegisterStmt) AddAnnotations(a *data.ClassValue) {
func (s *ClassRegisterStmt) AddAnnotations(a *data.ClassValue, decl *Annotation) {
if s.Class != nil {
s.Class.AddAnnotations(a)
s.Class.AddAnnotations(a, decl)
}
}

Expand Down Expand Up @@ -185,7 +185,7 @@ func applyClassAnnotations(vm data.VM, annotations []*Annotation, target AddAnno
}
}
if o, ok := obj.(*data.ClassValue); ok {
target.AddAnnotations(o)
target.AddAnnotations(o, an)
}
}
for i := len(callAnn) - 1; i >= 0; i-- {
Expand Down
5 changes: 4 additions & 1 deletion node/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,16 +243,19 @@ type Parameter struct {
Type data.TypeRef
DefaultValue data.GetValue // 默认值
Annotations []*data.ClassValue
AnnotationDecls []*Annotation
ConstructorClass string // Set only for parameters declared in a constructor.
}

func (p *Parameter) SetConstructorClass(name string) { p.ConstructorClass = name }

func (p *Parameter) AddAnnotations(a *data.ClassValue) {
func (p *Parameter) AddAnnotations(a *data.ClassValue, decl *Annotation) {
if p.Annotations == nil {
p.Annotations = []*data.ClassValue{}
p.AnnotationDecls = []*Annotation{}
}
p.Annotations = append(p.Annotations, a)
p.AnnotationDecls = append(p.AnnotationDecls, decl)
}

func (p *Parameter) GetDefaultValue() data.GetValue {
Expand Down
Loading
Loading